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 result_size number of elements in results array
593 * @param results pointer to already initialized MYSQL_BIND
594 * array (of sufficient size) for passing results
595 * @param processor function to call on each result
596 * @param processor_cls extra argument to processor
597 * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective
598 * values (size + buffer-reference for pointers); terminated
600 * @return GNUNET_SYSERR on error, otherwise
601 * the number of successfully affected (or queried) rows
604 prepared_statement_run_select (struct StatementHandle
605 *s, unsigned int result_size,
606 MYSQL_BIND * results,
607 GNUNET_MysqlDataProcessor
608 processor, void *processor_cls,
616 if (GNUNET_OK != prepare_statement (s))
619 return GNUNET_SYSERR;
621 va_start (ap, processor_cls);
622 if (GNUNET_OK != init_params (s, ap))
626 return GNUNET_SYSERR;
629 rsize = mysql_stmt_field_count (s->statement);
630 if (rsize > result_size)
633 return GNUNET_SYSERR;
635 if (mysql_stmt_bind_result (s->statement, results))
637 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
638 _("`%s' failed at %s:%d with error: %s\n"),
639 "mysql_stmt_bind_result",
640 __FILE__, __LINE__, mysql_stmt_error (s->statement));
641 return GNUNET_SYSERR;
647 ret = mysql_stmt_fetch (s->statement);
648 if (ret == MYSQL_NO_DATA)
652 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
653 _("`%s' failed at %s:%d with error: %s\n"),
655 __FILE__, __LINE__, mysql_stmt_error (s->statement));
656 return GNUNET_SYSERR;
658 if (processor != NULL)
659 if (GNUNET_OK != processor (processor_cls, rsize, results))
663 mysql_stmt_reset (s->statement);
669 get_node_uid (unsigned long long *nodeuid, const GNUNET_HashCode * peerHash)
672 struct GNUNET_CRYPTO_HashAsciiEncoded encPeer;
673 unsigned long long p_len;
676 memset (rbind, 0, sizeof (rbind));
677 rbind[0].buffer_type = MYSQL_TYPE_LONGLONG;
678 rbind[0].buffer = nodeuid;
679 rbind[0].is_unsigned = GNUNET_YES;
681 GNUNET_CRYPTO_hash_to_enc (peerHash, &encPeer);
682 p_len = strlen ((char *) &encPeer);
684 if (1 != (ret = prepared_statement_run_select (get_nodeuid,
692 MYSQL_TYPE_VAR_STRING,
698 fprintf (stderr, "FAILED\n");
700 return GNUNET_SYSERR;
706 get_current_trial (unsigned long long *trialuid)
710 memset (rbind, 0, sizeof (rbind));
711 rbind[0].buffer_type = MYSQL_TYPE_LONG;
712 rbind[0].is_unsigned = 1;
713 rbind[0].buffer = trialuid;
716 prepared_statement_run_select (get_trial,
719 return_ok, NULL, -1)))
721 return GNUNET_SYSERR;
728 get_current_topology (unsigned long long *topologyuid)
732 memset (rbind, 0, sizeof (rbind));
733 rbind[0].buffer_type = MYSQL_TYPE_LONGLONG;
734 rbind[0].is_unsigned = 1;
735 rbind[0].buffer = topologyuid;
738 prepared_statement_run_select (get_topology,
741 return_ok, NULL, -1)))
743 return GNUNET_SYSERR;
750 get_dhtkey_uid (unsigned long long *dhtkeyuid, const GNUNET_HashCode * key)
753 struct GNUNET_CRYPTO_HashAsciiEncoded encKey;
754 unsigned long long k_len;
755 memset (rbind, 0, sizeof (rbind));
756 rbind[0].buffer_type = MYSQL_TYPE_LONG;
757 rbind[0].is_unsigned = 1;
758 rbind[0].buffer = dhtkeyuid;
759 GNUNET_CRYPTO_hash_to_enc (key, &encKey);
760 k_len = strlen ((char *) &encKey);
762 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Searching for dhtkey `%s' in trial %llu\n", GNUNET_h2s(key), current_trial);
765 prepared_statement_run_select (get_dhtkeyuid,
769 MYSQL_TYPE_VAR_STRING,
777 return GNUNET_SYSERR;
784 * Run a prepared statement that does NOT produce results.
786 * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective
787 * values (size + buffer-reference for pointers); terminated
789 * @param insert_id NULL or address where to store the row ID of whatever
790 * was inserted (only for INSERT statements!)
791 * @return GNUNET_SYSERR on error, otherwise
792 * the number of successfully affected rows
795 prepared_statement_run (struct StatementHandle *s,
796 unsigned long long *insert_id, ...)
801 if (GNUNET_OK != prepare_statement(s))
804 return GNUNET_SYSERR;
806 GNUNET_assert(s->valid == GNUNET_YES);
807 if (s->statement == NULL)
808 return GNUNET_SYSERR;
810 va_start (ap, insert_id);
812 if (GNUNET_OK != init_params (s, ap))
815 return GNUNET_SYSERR;
819 affected = mysql_stmt_affected_rows (s->statement);
820 if (NULL != insert_id)
821 *insert_id = (unsigned long long) mysql_stmt_insert_id (s->statement);
822 mysql_stmt_reset (s->statement);
828 * Inserts the specified trial into the dhttests.trials table
830 * @param trial_info struct containing the data to insert about this trial
832 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
834 int add_trial (struct GNUNET_DHTLOG_TrialInfo *trial_info)
838 unsigned long long m_len;
839 m_len = strlen (trial_info->message);
841 stmt = mysql_stmt_init(conn);
843 (ret = prepared_statement_run (insert_trial, &trial_info->trialuid,
844 MYSQL_TYPE_LONG, &trial_info->other_identifier, GNUNET_YES,
845 MYSQL_TYPE_LONG, &trial_info->num_nodes, GNUNET_YES,
846 MYSQL_TYPE_LONG, &trial_info->topology, GNUNET_YES,
847 MYSQL_TYPE_FLOAT, &trial_info->topology_percentage,
848 MYSQL_TYPE_FLOAT, &trial_info->topology_probability,
849 MYSQL_TYPE_LONG, &trial_info->blacklist_topology, GNUNET_YES,
850 MYSQL_TYPE_LONG, &trial_info->connect_topology, GNUNET_YES,
851 MYSQL_TYPE_LONG, &trial_info->connect_topology_option, GNUNET_YES,
852 MYSQL_TYPE_FLOAT, &trial_info->connect_topology_option_modifier,
853 MYSQL_TYPE_LONG, &trial_info->puts, GNUNET_YES,
854 MYSQL_TYPE_LONG, &trial_info->gets, GNUNET_YES,
855 MYSQL_TYPE_LONG, &trial_info->concurrent, GNUNET_YES,
856 MYSQL_TYPE_LONG, &trial_info->settle_time, GNUNET_YES,
857 MYSQL_TYPE_LONG, &trial_info->num_rounds, GNUNET_YES,
858 MYSQL_TYPE_LONG, &trial_info->malicious_getters, GNUNET_YES,
859 MYSQL_TYPE_LONG, &trial_info->malicious_putters, GNUNET_YES,
860 MYSQL_TYPE_LONG, &trial_info->malicious_droppers, GNUNET_YES,
861 MYSQL_TYPE_LONG, &trial_info->malicious_get_frequency, GNUNET_YES,
862 MYSQL_TYPE_LONG, &trial_info->malicious_put_frequency, GNUNET_YES,
863 MYSQL_TYPE_LONG, &trial_info->stop_closest, GNUNET_YES,
864 MYSQL_TYPE_LONG, &trial_info->stop_found, GNUNET_YES,
865 MYSQL_TYPE_LONG, &trial_info->strict_kademlia, GNUNET_YES,
866 MYSQL_TYPE_LONG, &trial_info->gets_succeeded, GNUNET_YES,
867 MYSQL_TYPE_BLOB, trial_info->message, max_varchar_len +
868 max_varchar_len, &m_len,
871 if (ret == GNUNET_SYSERR)
873 mysql_stmt_close(stmt);
874 return GNUNET_SYSERR;
878 get_current_trial (¤t_trial);
880 mysql_stmt_close(stmt);
886 * Inserts the specified stats into the dhttests.node_statistics table
888 * @param peer the peer inserting the statistic
889 * @param route_requests route requests seen
890 * @param route_forwards route requests forwarded
891 * @param result_requests route result requests seen
892 * @param client_requests client requests initiated
893 * @param result_forwards route results forwarded
894 * @param gets get requests handled
895 * @param puts put requests handle
896 * @param data_inserts data inserted at this node
897 * @param find_peer_requests find peer requests seen
898 * @param find_peers_started find peer requests initiated at this node
899 * @param gets_started get requests initiated at this node
900 * @param puts_started put requests initiated at this node
901 * @param find_peer_responses_received find peer responses received locally
902 * @param get_responses_received get responses received locally
903 * @param find_peer_responses_sent find peer responses sent from this node
904 * @param get_responses_sent get responses sent from this node
906 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
909 add_stat (const struct GNUNET_PeerIdentity *peer, unsigned int route_requests,
910 unsigned int route_forwards, unsigned int result_requests,
911 unsigned int client_requests, unsigned int result_forwards,
912 unsigned int gets, unsigned int puts,
913 unsigned int data_inserts, unsigned int find_peer_requests,
914 unsigned int find_peers_started, unsigned int gets_started,
915 unsigned int puts_started, unsigned int find_peer_responses_received,
916 unsigned int get_responses_received, unsigned int find_peer_responses_sent,
917 unsigned int get_responses_sent)
921 unsigned long long peer_uid;
922 unsigned long long return_uid;
924 return GNUNET_SYSERR;
926 if (GNUNET_OK != get_node_uid (&peer_uid, &peer->hashPubKey))
928 return GNUNET_SYSERR;
931 stmt = mysql_stmt_init(conn);
933 (ret = prepared_statement_run (insert_stat,
935 MYSQL_TYPE_LONGLONG, ¤t_trial, GNUNET_YES,
936 MYSQL_TYPE_LONGLONG, &peer_uid, GNUNET_YES,
937 MYSQL_TYPE_LONG, &route_requests, GNUNET_YES,
938 MYSQL_TYPE_LONG, &route_forwards, GNUNET_YES,
939 MYSQL_TYPE_LONG, &result_requests, GNUNET_YES,
940 MYSQL_TYPE_LONG, &client_requests, GNUNET_YES,
941 MYSQL_TYPE_LONG, &result_forwards, GNUNET_YES,
942 MYSQL_TYPE_LONG, &gets, GNUNET_YES,
943 MYSQL_TYPE_LONG, &puts, GNUNET_YES,
944 MYSQL_TYPE_LONG, &data_inserts, GNUNET_YES,
945 MYSQL_TYPE_LONG, &find_peer_requests, GNUNET_YES,
946 MYSQL_TYPE_LONG, &find_peers_started, GNUNET_YES,
947 MYSQL_TYPE_LONG, &gets_started, GNUNET_YES,
948 MYSQL_TYPE_LONG, &puts_started, GNUNET_YES,
949 MYSQL_TYPE_LONG, &find_peer_responses_received, GNUNET_YES,
950 MYSQL_TYPE_LONG, &get_responses_received, GNUNET_YES,
951 MYSQL_TYPE_LONG, &find_peer_responses_sent, GNUNET_YES,
952 MYSQL_TYPE_LONG, &get_responses_sent, GNUNET_YES,
955 if (ret == GNUNET_SYSERR)
957 mysql_stmt_close(stmt);
958 return GNUNET_SYSERR;
962 mysql_stmt_close(stmt);
967 * Inserts the specified stats into the dhttests.generic_stats table
969 * @param peer the peer inserting the statistic
970 * @param name the name of the statistic
971 * @param section the section of the statistic
972 * @param value the value of the statistic
974 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
977 add_generic_stat (const struct GNUNET_PeerIdentity *peer,
979 const char *section, uint64_t value)
981 unsigned long long peer_uid;
982 unsigned long long section_len;
983 unsigned long long name_len;
986 return GNUNET_SYSERR;
988 if (GNUNET_OK != get_node_uid (&peer_uid, &peer->hashPubKey))
990 return GNUNET_SYSERR;
993 section_len = strlen(section);
994 name_len = strlen(name);
997 (ret = prepared_statement_run (insert_generic_stat,
999 MYSQL_TYPE_LONGLONG, ¤t_trial, GNUNET_YES,
1000 MYSQL_TYPE_LONGLONG, &peer_uid, GNUNET_YES,
1001 MYSQL_TYPE_VAR_STRING, §ion, max_varchar_len, §ion_len,
1002 MYSQL_TYPE_VAR_STRING, &name, max_varchar_len, &name_len,
1003 MYSQL_TYPE_LONGLONG, &value, GNUNET_YES,
1006 if (ret == GNUNET_SYSERR)
1008 return GNUNET_SYSERR;
1015 * Inserts the specified dhtkey into the dhttests.dhtkeys table,
1016 * stores return value of dhttests.dhtkeys.dhtkeyuid into dhtkeyuid
1018 * @param dhtkeyuid return value
1019 * @param dhtkey hashcode of key to insert
1021 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1024 add_dhtkey (unsigned long long *dhtkeyuid, const GNUNET_HashCode * dhtkey)
1028 struct GNUNET_CRYPTO_HashAsciiEncoded encKey;
1029 unsigned long long k_len;
1030 unsigned long long h_len;
1031 unsigned long long curr_dhtkeyuid;
1032 GNUNET_CRYPTO_hash_to_enc (dhtkey, &encKey);
1033 k_len = strlen ((char *) &encKey);
1034 h_len = sizeof (GNUNET_HashCode);
1036 ret = get_dhtkey_uid(&curr_dhtkeyuid, dhtkey);
1037 if (curr_dhtkeyuid != 0) /* dhtkey already exists */
1039 if (dhtkeyuid != NULL)
1040 *dhtkeyuid = curr_dhtkeyuid;
1043 else if (ret == GNUNET_SYSERR)
1046 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Failed to get dhtkeyuid!\n");
1051 (ret = prepared_statement_run (insert_dhtkey,
1053 MYSQL_TYPE_VAR_STRING,
1062 sizeof (GNUNET_HashCode),
1065 if (ret == GNUNET_SYSERR)
1067 return GNUNET_SYSERR;
1077 * Inserts the specified node into the dhttests.nodes table
1079 * @param nodeuid the inserted node uid
1080 * @param node the node to insert
1082 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1085 add_node (unsigned long long *nodeuid, struct GNUNET_PeerIdentity * node)
1087 struct GNUNET_CRYPTO_HashAsciiEncoded encPeer;
1088 unsigned long p_len;
1089 unsigned long h_len;
1093 return GNUNET_SYSERR;
1095 GNUNET_CRYPTO_hash_to_enc (&node->hashPubKey, &encPeer);
1096 p_len = (unsigned long) strlen ((char *) &encPeer);
1097 h_len = sizeof (GNUNET_HashCode);
1099 (ret = prepared_statement_run (insert_node,
1101 MYSQL_TYPE_LONGLONG, ¤t_trial, GNUNET_YES,
1102 MYSQL_TYPE_VAR_STRING, &encPeer, max_varchar_len, &p_len,
1103 MYSQL_TYPE_BLOB, &node->hashPubKey, sizeof (GNUNET_HashCode),
1106 if (ret == GNUNET_SYSERR)
1108 return GNUNET_SYSERR;
1115 * Update dhttests.trials table with current server time as end time
1117 * @param trialuid trial to update
1118 * @param gets_succeeded how many gets did the testcase report as successful
1120 * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1123 update_trials (unsigned long long trialuid,
1124 unsigned int gets_succeeded)
1129 (ret = prepared_statement_run (update_trial,
1131 MYSQL_TYPE_LONG, &gets_succeeded, GNUNET_YES,
1132 MYSQL_TYPE_LONGLONG, &trialuid, GNUNET_YES,
1135 if (ret == GNUNET_SYSERR)
1137 return GNUNET_SYSERR;
1143 return GNUNET_SYSERR;
1148 * Update dhttests.nodes table setting the identified
1149 * node as a malicious dropper.
1151 * @param peer the peer that was set to be malicious
1153 * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1155 int set_malicious (struct GNUNET_PeerIdentity *peer)
1157 unsigned long long p_len;
1161 temp_str = GNUNET_strdup(GNUNET_h2s_full(&peer->hashPubKey));
1162 p_len = strlen(temp_str);
1165 (ret = prepared_statement_run (update_node_malicious,
1167 MYSQL_TYPE_LONGLONG, ¤t_trial, GNUNET_YES,
1168 MYSQL_TYPE_VAR_STRING, temp_str, max_varchar_len, &p_len,
1171 if (ret == GNUNET_SYSERR)
1173 return GNUNET_SYSERR;
1181 * Update dhttests.trials table with total connections information
1183 * @param trialuid the trialuid to update
1184 * @param totalConnections the number of connections
1186 * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1189 add_connections (unsigned long long trialuid, unsigned int totalConnections)
1194 (ret = prepared_statement_run (update_connection,
1199 MYSQL_TYPE_LONGLONG,
1200 &trialuid, GNUNET_YES, -1)))
1202 if (ret == GNUNET_SYSERR)
1204 return GNUNET_SYSERR;
1210 return GNUNET_SYSERR;
1214 * Inserts the specified query into the dhttests.queries table
1216 * @param sqlqueruid inserted query uid
1217 * @param queryid dht query id
1218 * @param type type of the query
1219 * @param hops number of hops query traveled
1220 * @param succeeded whether or not query was successful
1221 * @param node the node the query hit
1222 * @param key the key of the query
1224 * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1227 add_query (unsigned long long *sqlqueryuid, unsigned long long queryid,
1228 unsigned int type, unsigned int hops, int succeeded,
1229 const struct GNUNET_PeerIdentity * node, const GNUNET_HashCode * key)
1232 unsigned long long peer_uid, key_uid;
1237 && (GNUNET_OK == get_node_uid (&peer_uid, &node->hashPubKey)))
1243 return GNUNET_SYSERR;
1246 if ((key != NULL) && (GNUNET_OK == get_dhtkey_uid (&key_uid, key)))
1250 else if ((key != NULL) && (key->bits[(512 / 8 / sizeof (unsigned int)) - 1] == 42)) /* Malicious marker */
1256 return GNUNET_SYSERR;
1260 (ret = prepared_statement_run (insert_query,
1262 MYSQL_TYPE_LONGLONG,
1271 MYSQL_TYPE_LONGLONG,
1274 MYSQL_TYPE_LONGLONG,
1280 MYSQL_TYPE_LONGLONG,
1281 &peer_uid, GNUNET_YES, -1)))
1283 if (ret == GNUNET_SYSERR)
1285 return GNUNET_SYSERR;
1291 return GNUNET_SYSERR;
1295 * Inserts the specified route information into the dhttests.routes table
1297 * @param sqlqueruid inserted query uid
1298 * @param queryid dht query id
1299 * @param type type of the query
1300 * @param hops number of hops query traveled
1301 * @param succeeded whether or not query was successful
1302 * @param node the node the query hit
1303 * @param key the key of the query
1304 * @param from_node the node that sent the message to node
1305 * @param to_node next node to forward message to
1307 * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1310 add_route (unsigned long long *sqlqueryuid, unsigned long long queryid,
1311 unsigned int type, unsigned int hops,
1312 int succeeded, const struct GNUNET_PeerIdentity * node,
1313 const GNUNET_HashCode * key, const struct GNUNET_PeerIdentity * from_node,
1314 const struct GNUNET_PeerIdentity * to_node)
1316 unsigned long long peer_uid = 0;
1317 unsigned long long key_uid = 0;
1318 unsigned long long from_uid = 0;
1319 unsigned long long to_uid = 0;
1322 if (from_node != NULL)
1323 get_node_uid (&from_uid, &from_node->hashPubKey);
1327 if (to_node != NULL)
1328 get_node_uid (&to_uid, &to_node->hashPubKey);
1334 if (1 != get_node_uid (&peer_uid, &node->hashPubKey))
1336 return GNUNET_SYSERR;
1340 return GNUNET_SYSERR;
1344 if (1 != get_dhtkey_uid (&key_uid, key))
1346 return GNUNET_SYSERR;
1350 return GNUNET_SYSERR;
1353 (ret = prepared_statement_run (insert_route,
1355 MYSQL_TYPE_LONGLONG,
1364 MYSQL_TYPE_LONGLONG,
1367 MYSQL_TYPE_LONGLONG,
1373 MYSQL_TYPE_LONGLONG,
1376 MYSQL_TYPE_LONGLONG,
1379 MYSQL_TYPE_LONGLONG,
1380 &to_uid, GNUNET_YES, -1)))
1382 if (ret == GNUNET_SYSERR)
1384 return GNUNET_SYSERR;
1390 return GNUNET_SYSERR;
1394 * Update dhttests.topology table with total connections information
1396 * @param totalConnections the number of connections
1398 * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1401 update_current_topology (unsigned int connections)
1404 unsigned long long topologyuid;
1406 get_current_topology(&topologyuid);
1409 (ret = prepared_statement_run (update_topology,
1414 MYSQL_TYPE_LONGLONG,
1415 &topologyuid, GNUNET_YES, -1)))
1417 if (ret == GNUNET_SYSERR)
1419 return GNUNET_SYSERR;
1425 return GNUNET_SYSERR;
1430 * Records the current topology (number of connections, time, trial)
1432 * @param num_connections how many connections are in the topology
1434 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1437 add_topology (int num_connections)
1442 (ret = prepared_statement_run (insert_topology,
1444 MYSQL_TYPE_LONGLONG,
1451 if (ret == GNUNET_SYSERR)
1453 return GNUNET_SYSERR;
1459 return GNUNET_SYSERR;
1464 * Records a connection between two peers in the current topology
1466 * @param first one side of the connection
1467 * @param second other side of the connection
1469 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1472 add_extended_topology (const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second)
1475 unsigned long long first_uid;
1476 unsigned long long second_uid;
1477 unsigned long long topologyuid;
1479 if (GNUNET_OK != get_current_topology(&topologyuid))
1480 return GNUNET_SYSERR;
1481 if (GNUNET_OK != get_node_uid(&first_uid, &first->hashPubKey))
1482 return GNUNET_SYSERR;
1483 if (GNUNET_OK != get_node_uid(&second_uid, &second->hashPubKey))
1484 return GNUNET_SYSERR;
1487 (ret = prepared_statement_run (extend_topology,
1489 MYSQL_TYPE_LONGLONG,
1492 MYSQL_TYPE_LONGLONG,
1495 MYSQL_TYPE_LONGLONG,
1499 if (ret == GNUNET_SYSERR)
1501 return GNUNET_SYSERR;
1507 return GNUNET_SYSERR;
1513 * Provides the dhtlog api
1515 * @param c the configuration to use to connect to a server
1517 * @return the handle to the server, or NULL on error
1520 libgnunet_plugin_dhtlog_mysql_init (void * cls)
1522 struct GNUNET_DHTLOG_Plugin *plugin = cls;
1525 max_varchar_len = 255;
1527 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MySQL DHT Logger: initializing database\n");
1530 if (iopen (plugin) != GNUNET_OK)
1532 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1533 _("Failed to initialize MySQL database connection for dhtlog.\n"));
1537 GNUNET_assert(plugin->dhtlog_api == NULL);
1538 plugin->dhtlog_api = GNUNET_malloc(sizeof(struct GNUNET_DHTLOG_Handle));
1539 plugin->dhtlog_api->insert_trial = &add_trial;
1540 plugin->dhtlog_api->insert_stat = &add_stat;
1541 plugin->dhtlog_api->add_generic_stat = &add_generic_stat;
1542 plugin->dhtlog_api->insert_query = &add_query;
1543 plugin->dhtlog_api->update_trial = &update_trials;
1544 plugin->dhtlog_api->insert_route = &add_route;
1545 plugin->dhtlog_api->insert_node = &add_node;
1546 plugin->dhtlog_api->insert_dhtkey = &add_dhtkey;
1547 plugin->dhtlog_api->update_connections = &add_connections;
1548 plugin->dhtlog_api->insert_topology = &add_topology;
1549 plugin->dhtlog_api->update_topology = &update_current_topology;
1550 plugin->dhtlog_api->insert_extended_topology = &add_extended_topology;
1551 plugin->dhtlog_api->set_malicious = &set_malicious;
1552 plugin->dhtlog_api->add_generic_stat = &add_generic_stat;
1553 get_current_trial (¤t_trial);
1559 * Shutdown the plugin.
1562 libgnunet_plugin_dhtlog_mysql_done (void * cls)
1564 struct GNUNET_DHTLOG_Handle *dhtlog_api = cls;
1566 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1567 "MySQL DHT Logger: database shutdown\n");
1568 GNUNET_assert(dhtlog_api != NULL);
1569 prepared_statement_close(insert_query);
1570 prepared_statement_close(insert_route);
1571 prepared_statement_close(insert_trial);
1572 prepared_statement_close(insert_node);
1573 prepared_statement_close(insert_dhtkey);
1574 prepared_statement_close(update_trial);
1575 prepared_statement_close(get_dhtkeyuid);
1576 prepared_statement_close(get_nodeuid);
1577 prepared_statement_close(update_connection);
1578 prepared_statement_close(get_trial);
1579 prepared_statement_close(get_topology);
1580 prepared_statement_close(insert_topology);
1581 prepared_statement_close(update_topology);
1582 prepared_statement_close(extend_topology);
1583 prepared_statement_close(update_node_malicious);
1588 mysql_library_end();
1589 GNUNET_free(dhtlog_api);
1593 /* end of plugin_dhtlog_mysql.c */