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_NO
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, 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, message) "\
113 "VALUES (NOW(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
115 static struct StatementHandle *insert_trial;
117 #define INSERT_STAT_STMT "INSERT INTO node_statistics"\
118 "(trialuid, nodeuid, route_requests,"\
119 "route_forwards, result_requests,"\
120 "client_results, result_forwards, gets,"\
121 "puts, data_inserts, find_peer_requests, "\
122 "find_peers_started, gets_started, puts_started, find_peer_responses_received,"\
123 "get_responses_received, find_peer_responses_sent, get_responses_sent) "\
124 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
126 static struct StatementHandle *insert_stat;
128 #define INSERT_DHTKEY_STMT "INSERT INTO dhtkeys (dhtkey, trialuid, keybits) "\
130 static struct StatementHandle *insert_dhtkey;
132 #define UPDATE_TRIALS_STMT "UPDATE trials set endtime=NOW(), total_messages_dropped = ?, total_bytes_dropped = ?, unknownPeers = ? where trialuid = ?"
133 static struct StatementHandle *update_trial;
135 #define UPDATE_CONNECTIONS_STMT "UPDATE trials set totalConnections = ? where trialuid = ?"
136 static struct StatementHandle *update_connection;
138 #define GET_TRIAL_STMT "SELECT MAX( trialuid ) FROM trials"
139 static struct StatementHandle *get_trial;
141 #define GET_TOPOLOGY_STMT "SELECT MAX( topology_uid ) FROM topology"
142 static struct StatementHandle *get_topology;
144 #define GET_DHTKEYUID_STMT "SELECT dhtkeyuid FROM dhtkeys where dhtkey = ? and trialuid = ?"
145 static struct StatementHandle *get_dhtkeyuid;
147 #define GET_NODEUID_STMT "SELECT nodeuid FROM nodes where trialuid = ? and nodeid = ?"
148 static struct StatementHandle *get_nodeuid;
150 #define INSERT_TOPOLOGY_STMT "INSERT INTO topology (trialuid, date, connections) "\
151 "VALUES (?, NOW(), ?)"
152 static struct StatementHandle *insert_topology;
154 #define EXTEND_TOPOLOGY_STMT "INSERT INTO extended_topology (topology_uid, uid_first, uid_second) "\
156 static struct StatementHandle *extend_topology;
158 #define UPDATE_TOPOLOGY_STMT "update topology set connections = ? where topology_uid = ?"
159 static struct StatementHandle *update_topology;
162 * Run a query (not a select statement)
164 * @return GNUNET_OK if executed, GNUNET_SYSERR if an error occurred
167 run_statement (const char *statement)
169 mysql_query (conn, statement);
170 if (mysql_error (conn)[0])
172 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
174 return GNUNET_SYSERR;
180 * Creates tables if they don't already exist for dht logging
185 #define MRUNS(a) (GNUNET_OK != run_statement (a) )
187 if (MRUNS ("CREATE TABLE IF NOT EXISTS `dhtkeys` ("
188 "dhtkeyuid int(10) unsigned NOT NULL auto_increment COMMENT 'Unique Key given to each query',"
189 "`dhtkey` varchar(255) NOT NULL COMMENT 'The ASCII value of the key being searched for',"
190 "trialuid int(10) unsigned NOT NULL,"
191 "keybits blob NOT NULL,"
192 "UNIQUE KEY `dhtkeyuid` (`dhtkeyuid`)"
193 ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1"))
194 return GNUNET_SYSERR;
196 if (MRUNS ("CREATE TABLE IF NOT EXISTS `nodes` ("
197 "`nodeuid` int(10) unsigned NOT NULL auto_increment,"
198 "`trialuid` int(10) unsigned NOT NULL,"
199 "`nodeid` varchar(255) NOT NULL,"
200 "`nodebits` blob NOT NULL,"
201 "PRIMARY KEY (`nodeuid`)"
202 ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1"))
203 return GNUNET_SYSERR;
205 if (MRUNS ("CREATE TABLE IF NOT EXISTS `queries` ("
206 "`trialuid` int(10) unsigned NOT NULL,"
207 "`queryuid` int(10) unsigned NOT NULL auto_increment,"
208 "`dhtqueryid` bigint(20) NOT NULL,"
209 "`querytype` enum('1','2','3','4','5') NOT NULL,"
210 "`hops` int(10) unsigned NOT NULL,"
211 "`succeeded` tinyint NOT NULL,"
212 "`nodeuid` int(10) unsigned NOT NULL,"
213 "`time` timestamp NOT NULL default CURRENT_TIMESTAMP,"
214 "`dhtkeyuid` int(10) unsigned NOT NULL,"
215 "PRIMARY KEY (`queryuid`)"
216 ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1"))
217 return GNUNET_SYSERR;
219 if (MRUNS ("CREATE TABLE IF NOT EXISTS `routes` ("
220 "`trialuid` int(10) unsigned NOT NULL,"
221 "`queryuid` int(10) unsigned NOT NULL auto_increment,"
222 "`dhtqueryid` bigint(20) NOT NULL,"
223 "`querytype` enum('1','2','3','4','5') NOT NULL,"
224 "`hops` int(10) unsigned NOT NULL,"
225 "`succeeded` tinyint NOT NULL,"
226 "`nodeuid` int(10) unsigned NOT NULL,"
227 "`time` timestamp NOT NULL default CURRENT_TIMESTAMP,"
228 "`dhtkeyuid` int(10) unsigned NOT NULL,"
229 "`from_node` int(10) unsigned NOT NULL,"
230 "`to_node` int(10) unsigned NOT NULL,"
231 "PRIMARY KEY (`queryuid`)"
232 ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1"))
233 return GNUNET_SYSERR;
235 if (MRUNS ("CREATE TABLE IF NOT EXISTS `trials` ("
236 "`trialuid` int(10) unsigned NOT NULL auto_increment,"
237 "`numnodes` int(10) unsigned NOT NULL,"
238 "`topology` int(10) NOT NULL,"
239 "`starttime` datetime NOT NULL,"
240 "`endtime` datetime NOT NULL,"
241 "`puts` int(10) unsigned NOT NULL,"
242 "`gets` int(10) unsigned NOT NULL,"
243 "`concurrent` int(10) unsigned NOT NULL,"
244 "`settle_time` int(10) unsigned NOT NULL,"
245 "`totalConnections` int(10) unsigned NOT NULL,"
246 "`message` text NOT NULL,"
247 "`num_rounds` int(10) unsigned NOT NULL,"
248 "`malicious_getters` int(10) unsigned NOT NULL,"
249 "`malicious_putters` int(10) unsigned NOT NULL,"
250 "`malicious_droppers` int(10) unsigned NOT NULL,"
251 "`totalMessagesDropped` int(10) unsigned NOT NULL,"
252 "`totalBytesDropped` int(10) unsigned NOT NULL,"
253 "`topology_modifier` double NOT NULL,"
254 "`logNMultiplier` double NOT NULL,"
255 "`maxnetbps` bigint(20) unsigned NOT NULL,"
256 "`unknownPeers` int(10) unsigned NOT NULL,"
257 "PRIMARY KEY (`trialuid`),"
258 "UNIQUE KEY `trialuid` (`trialuid`)"
259 ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1"))
260 return GNUNET_SYSERR;
262 if (MRUNS ("CREATE TABLE IF NOT EXISTS `topology` ("
263 "`topology_uid` int(10) unsigned NOT NULL AUTO_INCREMENT,"
264 "`trialuid` int(10) unsigned NOT NULL,"
265 "`date` datetime NOT NULL,"
266 "`connections` int(10) unsigned NOT NULL,"
267 "PRIMARY KEY (`topology_uid`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1"))
268 return GNUNET_SYSERR;
270 if (MRUNS ("CREATE TABLE IF NOT EXISTS `extended_topology` ("
271 "`extended_uid` int(10) unsigned NOT NULL AUTO_INCREMENT,"
272 "`topology_uid` int(10) unsigned NOT NULL,"
273 "`uid_first` int(10) unsigned NOT NULL,"
274 "`uid_second` int(10) unsigned NOT NULL,"
275 "PRIMARY KEY (`extended_uid`)"
276 ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1"))
277 return GNUNET_SYSERR;
279 if (MRUNS ("CREATE TABLE IF NOT EXISTS `node_statistics` ("
280 "`stat_uid` int(10) unsigned NOT NULL AUTO_INCREMENT,"
281 "`trialuid` int(10) unsigned NOT NULL,"
282 "`nodeuid` int(10) unsigned NOT NULL,"
283 "`route_requests` int(10) unsigned NOT NULL,"
284 "`route_forwards` int(10) unsigned NOT NULL,"
285 "`result_requests` int(10) unsigned NOT NULL,"
286 "`client_results` int(10) unsigned NOT NULL,"
287 "`result_forwards` int(10) unsigned NOT NULL,"
288 "`gets` int(10) unsigned NOT NULL,"
289 "`puts` int(10) unsigned NOT NULL,"
290 "`data_inserts` int(10) unsigned NOT NULL,"
291 "`find_peer_requests` int(10) unsigned NOT NULL,"
292 "`find_peers_started` int(10) unsigned NOT NULL,"
293 "`gets_started` int(10) unsigned NOT NULL,"
294 "`puts_started` int(10) unsigned NOT NULL,"
295 "`find_peer_responses_received` int(10) unsigned NOT NULL,"
296 "`get_responses_received` int(10) unsigned NOT NULL,"
297 "`find_peer_responses_sent` int(10) unsigned NOT NULL,"
298 "`get_responses_sent` int(10) unsigned NOT NULL,"
299 "PRIMARY KEY (`stat_uid`)"
300 ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;"))
301 return GNUNET_SYSERR;
303 if (MRUNS ("SET AUTOCOMMIT = 1"))
304 return GNUNET_SYSERR;
311 * Create a prepared statement.
313 * @return NULL on error
315 struct StatementHandle *
316 prepared_statement_create (const char *statement)
318 struct StatementHandle *ret;
320 ret = GNUNET_malloc (sizeof (struct StatementHandle));
321 ret->query = GNUNET_strdup (statement);
326 * Close a prepared statement.
328 * @return NULL on error
331 prepared_statement_close (struct StatementHandle *s)
338 GNUNET_free_non_null(s->query);
340 if (s->valid == GNUNET_YES)
341 mysql_stmt_close(s->statement);
346 * Initialize the prepared statements for use with dht test logging
349 iopen (struct GNUNET_DHTLOG_Plugin *plugin)
353 unsigned int timeout;
358 unsigned long long port;
360 conn = mysql_init (NULL);
362 return GNUNET_SYSERR;
364 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (plugin->cfg,
368 database = GNUNET_strdup("gnunet");
371 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (plugin->cfg,
372 "MYSQL", "USER", &user))
374 user = GNUNET_strdup("dht");
377 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (plugin->cfg,
378 "MYSQL", "PASSWORD", &password))
380 password = GNUNET_strdup("dhttest**");
383 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (plugin->cfg,
384 "MYSQL", "SERVER", &server))
386 server = GNUNET_strdup("localhost");
389 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (plugin->cfg,
390 "MYSQL", "MYSQL_PORT", &port))
395 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to mysql with: user %s, pass %s, server %s, database %s, port %d\n",
396 user, password, server, database, port);
399 timeout = 60; /* in seconds */
400 mysql_options (conn, MYSQL_OPT_RECONNECT, &reconnect);
402 MYSQL_OPT_CONNECT_TIMEOUT, (const void *) &timeout);
403 mysql_options(conn, MYSQL_SET_CHARSET_NAME, "UTF8");
404 mysql_options (conn, MYSQL_OPT_READ_TIMEOUT, (const void *) &timeout);
405 mysql_options (conn, MYSQL_OPT_WRITE_TIMEOUT, (const void *) &timeout);
406 mysql_real_connect (conn, server, user, password,
407 database, (unsigned int) port, NULL, CLIENT_IGNORE_SIGPIPE);
409 GNUNET_free_non_null(server);
410 GNUNET_free_non_null(password);
411 GNUNET_free_non_null(user);
412 GNUNET_free_non_null(database);
414 if (mysql_error (conn)[0])
416 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
417 "mysql_real_connect");
418 return GNUNET_SYSERR;
422 db = GNUNET_MYSQL_database_open (coreAPI->ectx, coreAPI->cfg);
424 return GNUNET_SYSERR;
429 #define PINIT(a,b) (NULL == (a = prepared_statement_create(b)))
430 if (PINIT (insert_query, INSERT_QUERIES_STMT) ||
431 PINIT (insert_route, INSERT_ROUTES_STMT) ||
432 PINIT (insert_trial, INSERT_TRIALS_STMT) ||
433 PINIT (insert_stat, INSERT_STAT_STMT) ||
434 PINIT (insert_node, INSERT_NODES_STMT) ||
435 PINIT (insert_dhtkey, INSERT_DHTKEY_STMT) ||
436 PINIT (update_trial, UPDATE_TRIALS_STMT) ||
437 PINIT (get_dhtkeyuid, GET_DHTKEYUID_STMT) ||
438 PINIT (get_nodeuid, GET_NODEUID_STMT) ||
439 PINIT (update_connection, UPDATE_CONNECTIONS_STMT) ||
440 PINIT (get_trial, GET_TRIAL_STMT) ||
441 PINIT (get_topology, GET_TOPOLOGY_STMT) ||
442 PINIT (insert_topology, INSERT_TOPOLOGY_STMT)||
443 PINIT (update_topology, UPDATE_TOPOLOGY_STMT)||
444 PINIT (extend_topology, EXTEND_TOPOLOGY_STMT))
446 return GNUNET_SYSERR;
454 return_ok (void *cls, unsigned int num_values, MYSQL_BIND * values)
460 * Prepare a statement for running.
462 * @return GNUNET_OK on success
465 prepare_statement (struct StatementHandle *ret)
467 if (GNUNET_YES == ret->valid)
470 ret->statement = mysql_stmt_init (conn);
471 if (ret->statement == NULL)
472 return GNUNET_SYSERR;
474 if (mysql_stmt_prepare (ret->statement, ret->query, strlen (ret->query)))
476 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
477 "mysql_stmt_prepare `%s', %s", ret->query, mysql_error(conn));
478 mysql_stmt_close (ret->statement);
479 ret->statement = NULL;
480 return GNUNET_SYSERR;
482 ret->valid = GNUNET_YES;
487 * Bind the parameters for the given MySQL statement
490 * @param s statement to bind and run
491 * @param ap arguments for the binding
492 * @return GNUNET_SYSERR on error, GNUNET_OK on success
495 init_params (struct StatementHandle *s, va_list ap)
497 MYSQL_BIND qbind[MAX_PARAM];
500 enum enum_field_types ft;
502 pc = mysql_stmt_param_count (s->statement);
505 /* increase internal constant! */
507 return GNUNET_SYSERR;
509 memset (qbind, 0, sizeof (qbind));
512 while ((pc > 0) && (-1 != (ft = va_arg (ap, enum enum_field_types))))
514 qbind[off].buffer_type = ft;
517 case MYSQL_TYPE_FLOAT:
518 qbind[off].buffer = va_arg (ap, float *);
520 case MYSQL_TYPE_LONGLONG:
521 qbind[off].buffer = va_arg (ap, unsigned long long *);
522 qbind[off].is_unsigned = va_arg (ap, int);
524 case MYSQL_TYPE_LONG:
525 qbind[off].buffer = va_arg (ap, unsigned int *);
526 qbind[off].is_unsigned = va_arg (ap, int);
528 case MYSQL_TYPE_VAR_STRING:
529 case MYSQL_TYPE_STRING:
530 case MYSQL_TYPE_BLOB:
531 qbind[off].buffer = va_arg (ap, void *);
532 qbind[off].buffer_length = va_arg (ap, unsigned long);
533 qbind[off].length = va_arg (ap, unsigned long *);
536 /* unsupported type */
538 return GNUNET_SYSERR;
543 if (!((pc == 0) && (ft != -1) && (va_arg (ap, int) == -1)))
546 return GNUNET_SYSERR;
548 if (mysql_stmt_bind_param (s->statement, qbind))
550 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
551 _("`%s' failed at %s:%d with error: %s\n"),
552 "mysql_stmt_bind_param",
553 __FILE__, __LINE__, mysql_stmt_error (s->statement));
554 return GNUNET_SYSERR;
557 if (mysql_stmt_execute (s->statement))
559 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
560 _("`%s' failed at %s:%d with error: %s\n"),
561 "mysql_stmt_execute",
562 __FILE__, __LINE__, mysql_stmt_error (s->statement));
563 return GNUNET_SYSERR;
570 * Run a prepared SELECT statement.
572 * @param result_size number of elements in results array
573 * @param results pointer to already initialized MYSQL_BIND
574 * array (of sufficient size) for passing results
575 * @param processor function to call on each result
576 * @param processor_cls extra argument to processor
577 * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective
578 * values (size + buffer-reference for pointers); terminated
580 * @return GNUNET_SYSERR on error, otherwise
581 * the number of successfully affected (or queried) rows
584 prepared_statement_run_select (struct StatementHandle
585 *s, unsigned int result_size,
586 MYSQL_BIND * results,
587 GNUNET_MysqlDataProcessor
588 processor, void *processor_cls,
596 if (GNUNET_OK != prepare_statement (s))
599 return GNUNET_SYSERR;
601 va_start (ap, processor_cls);
602 if (GNUNET_OK != init_params (s, ap))
606 return GNUNET_SYSERR;
609 rsize = mysql_stmt_field_count (s->statement);
610 if (rsize > result_size)
613 return GNUNET_SYSERR;
615 if (mysql_stmt_bind_result (s->statement, results))
617 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
618 _("`%s' failed at %s:%d with error: %s\n"),
619 "mysql_stmt_bind_result",
620 __FILE__, __LINE__, mysql_stmt_error (s->statement));
621 return GNUNET_SYSERR;
627 ret = mysql_stmt_fetch (s->statement);
628 if (ret == MYSQL_NO_DATA)
632 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
633 _("`%s' failed at %s:%d with error: %s\n"),
635 __FILE__, __LINE__, mysql_stmt_error (s->statement));
636 return GNUNET_SYSERR;
638 if (processor != NULL)
639 if (GNUNET_OK != processor (processor_cls, rsize, results))
643 mysql_stmt_reset (s->statement);
649 get_node_uid (unsigned long long *nodeuid, const GNUNET_HashCode * peerHash)
652 struct GNUNET_CRYPTO_HashAsciiEncoded encPeer;
653 unsigned long long p_len;
656 memset (rbind, 0, sizeof (rbind));
657 rbind[0].buffer_type = MYSQL_TYPE_LONGLONG;
658 rbind[0].buffer = nodeuid;
659 rbind[0].is_unsigned = GNUNET_YES;
661 GNUNET_CRYPTO_hash_to_enc (peerHash, &encPeer);
662 p_len = strlen ((char *) &encPeer);
664 if (1 != (ret = prepared_statement_run_select (get_nodeuid,
672 MYSQL_TYPE_VAR_STRING,
678 fprintf (stderr, "FAILED\n");
680 return GNUNET_SYSERR;
686 get_current_trial (unsigned long long *trialuid)
690 memset (rbind, 0, sizeof (rbind));
691 rbind[0].buffer_type = MYSQL_TYPE_LONG;
692 rbind[0].is_unsigned = 1;
693 rbind[0].buffer = trialuid;
696 prepared_statement_run_select (get_trial,
699 return_ok, NULL, -1)))
701 return GNUNET_SYSERR;
708 get_current_topology (unsigned long long *topologyuid)
712 memset (rbind, 0, sizeof (rbind));
713 rbind[0].buffer_type = MYSQL_TYPE_LONGLONG;
714 rbind[0].is_unsigned = 1;
715 rbind[0].buffer = topologyuid;
718 prepared_statement_run_select (get_topology,
721 return_ok, NULL, -1)))
723 return GNUNET_SYSERR;
730 get_dhtkey_uid (unsigned long long *dhtkeyuid, const GNUNET_HashCode * key)
733 struct GNUNET_CRYPTO_HashAsciiEncoded encKey;
734 unsigned long long k_len;
735 memset (rbind, 0, sizeof (rbind));
736 rbind[0].buffer_type = MYSQL_TYPE_LONG;
737 rbind[0].is_unsigned = 1;
738 rbind[0].buffer = dhtkeyuid;
739 GNUNET_CRYPTO_hash_to_enc (key, &encKey);
740 k_len = strlen ((char *) &encKey);
743 prepared_statement_run_select (get_dhtkeyuid,
747 MYSQL_TYPE_VAR_STRING,
755 return GNUNET_SYSERR;
762 * Run a prepared statement that does NOT produce results.
764 * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective
765 * values (size + buffer-reference for pointers); terminated
767 * @param insert_id NULL or address where to store the row ID of whatever
768 * was inserted (only for INSERT statements!)
769 * @return GNUNET_SYSERR on error, otherwise
770 * the number of successfully affected rows
773 prepared_statement_run (struct StatementHandle *s,
774 unsigned long long *insert_id, ...)
779 if (GNUNET_OK != prepare_statement(s))
782 return GNUNET_SYSERR;
784 GNUNET_assert(s->valid == GNUNET_YES);
785 if (s->statement == NULL)
786 return GNUNET_SYSERR;
788 va_start (ap, insert_id);
790 if (GNUNET_OK != init_params (s, ap))
793 return GNUNET_SYSERR;
797 affected = mysql_stmt_affected_rows (s->statement);
798 if (NULL != insert_id)
799 *insert_id = (unsigned long long) mysql_stmt_insert_id (s->statement);
800 mysql_stmt_reset (s->statement);
806 * Inserts the specified trial into the dhttests.trials table
808 * @param trialuid return the trialuid of the newly inserted trial
809 * @param num_nodes how many nodes are in the trial
810 * @param topology integer representing topology for this trial
811 * @param blacklist_topology integer representing blacklist topology for this trial
812 * @param connect_topology integer representing connect topology for this trial
813 * @param connect_topology_option integer representing connect topology option
814 * @param connect_topology_option_modifier float to modify connect option
815 * @param topology_percentage percentage modifier for certain topologies
816 * @param topology_probability probability modifier for certain topologies
817 * @param puts number of puts to perform
818 * @param gets number of gets to perform
819 * @param concurrent number of concurrent requests
820 * @param settle_time time to wait between creating topology and starting testing
821 * @param num_rounds number of times to repeat the trial
822 * @param malicious_getters number of malicious GET peers in the trial
823 * @param malicious_putters number of malicious PUT peers in the trial
824 * @param malicious_droppers number of malicious DROP peers in the trial
825 * @param message string to put into DB for this trial
827 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
830 add_trial (unsigned long long *trialuid, int num_nodes, int topology,
831 int blacklist_topology, int connect_topology,
832 int connect_topology_option, float connect_topology_option_modifier,
833 float topology_percentage, float topology_probability,
834 int puts, int gets, int concurrent, int settle_time,
835 int num_rounds, int malicious_getters, int malicious_putters,
836 int malicious_droppers, char *message)
840 unsigned long long m_len;
841 m_len = strlen (message);
843 stmt = mysql_stmt_init(conn);
845 (ret = prepared_statement_run (insert_trial,
854 &topology_percentage,
856 &topology_probability,
864 &connect_topology_option,
867 &connect_topology_option_modifier,
895 max_varchar_len, &m_len,
898 if (ret == GNUNET_SYSERR)
900 mysql_stmt_close(stmt);
901 return GNUNET_SYSERR;
905 get_current_trial (¤t_trial);
907 mysql_stmt_close(stmt);
913 * Inserts the specified stats into the dhttests.node_statistics table
915 * @param peer the peer inserting the statistic
916 * @param route_requests route requests seen
917 * @param route_forwards route requests forwarded
918 * @param result_requests route result requests seen
919 * @param client_requests client requests initiated
920 * @param result_forwards route results forwarded
921 * @param gets get requests handled
922 * @param puts put requests handle
923 * @param data_inserts data inserted at this node
924 * @param find_peer_requests find peer requests seen
925 * @param find_peers_started find peer requests initiated at this node
926 * @param gets_started get requests initiated at this node
927 * @param puts_started put requests initiated at this node
928 * @param find_peer_responses_received find peer responses received locally
929 * @param get_responses_received get responses received locally
930 * @param find_peer_responses_sent find peer responses sent from this node
931 * @param get_responses_sent get responses sent from this node
933 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
936 add_stat (const struct GNUNET_PeerIdentity *peer, unsigned int route_requests,
937 unsigned int route_forwards, unsigned int result_requests,
938 unsigned int client_requests, unsigned int result_forwards,
939 unsigned int gets, unsigned int puts,
940 unsigned int data_inserts, unsigned int find_peer_requests,
941 unsigned int find_peers_started, unsigned int gets_started,
942 unsigned int puts_started, unsigned int find_peer_responses_received,
943 unsigned int get_responses_received, unsigned int find_peer_responses_sent,
944 unsigned int get_responses_sent)
948 unsigned long long peer_uid;
949 unsigned long long return_uid;
951 return GNUNET_SYSERR;
953 if (GNUNET_OK != get_node_uid (&peer_uid, &peer->hashPubKey))
955 return GNUNET_SYSERR;
958 stmt = mysql_stmt_init(conn);
960 (ret = prepared_statement_run (insert_stat,
962 MYSQL_TYPE_LONGLONG, ¤t_trial, GNUNET_YES,
963 MYSQL_TYPE_LONGLONG, &peer_uid, GNUNET_YES,
964 MYSQL_TYPE_LONG, &route_requests, GNUNET_YES,
965 MYSQL_TYPE_LONG, &route_forwards, GNUNET_YES,
966 MYSQL_TYPE_LONG, &result_requests, GNUNET_YES,
967 MYSQL_TYPE_LONG, &client_requests, GNUNET_YES,
968 MYSQL_TYPE_LONG, &result_forwards, GNUNET_YES,
969 MYSQL_TYPE_LONG, &gets, GNUNET_YES,
970 MYSQL_TYPE_LONG, &puts, GNUNET_YES,
971 MYSQL_TYPE_LONG, &data_inserts, GNUNET_YES,
972 MYSQL_TYPE_LONG, &find_peer_requests, GNUNET_YES,
973 MYSQL_TYPE_LONG, &find_peers_started, GNUNET_YES,
974 MYSQL_TYPE_LONG, &gets_started, GNUNET_YES,
975 MYSQL_TYPE_LONG, &puts_started, GNUNET_YES,
976 MYSQL_TYPE_LONG, &find_peer_responses_received, GNUNET_YES,
977 MYSQL_TYPE_LONG, &get_responses_received, GNUNET_YES,
978 MYSQL_TYPE_LONG, &find_peer_responses_sent, GNUNET_YES,
979 MYSQL_TYPE_LONG, &get_responses_sent, GNUNET_YES,
982 if (ret == GNUNET_SYSERR)
984 mysql_stmt_close(stmt);
985 return GNUNET_SYSERR;
989 mysql_stmt_close(stmt);
994 * Inserts the specified dhtkey into the dhttests.dhtkeys table,
995 * stores return value of dhttests.dhtkeys.dhtkeyuid into dhtkeyuid
997 * @param dhtkeyuid return value
998 * @param dhtkey hashcode of key to insert
1000 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1003 add_dhtkey (unsigned long long *dhtkeyuid, const GNUNET_HashCode * dhtkey)
1007 struct GNUNET_CRYPTO_HashAsciiEncoded encKey;
1008 unsigned long long k_len;
1009 unsigned long long h_len;
1010 unsigned long long curr_dhtkeyuid;
1011 GNUNET_CRYPTO_hash_to_enc (dhtkey, &encKey);
1012 k_len = strlen ((char *) &encKey);
1013 h_len = sizeof (GNUNET_HashCode);
1015 ret = get_dhtkey_uid(&curr_dhtkeyuid, dhtkey);
1016 if (curr_dhtkeyuid != 0) /* dhtkey already exists */
1018 if (dhtkeyuid != NULL)
1019 *dhtkeyuid = curr_dhtkeyuid;
1024 (ret = prepared_statement_run (insert_dhtkey,
1026 MYSQL_TYPE_VAR_STRING,
1035 sizeof (GNUNET_HashCode),
1038 if (ret == GNUNET_SYSERR)
1040 return GNUNET_SYSERR;
1050 * Inserts the specified node into the dhttests.nodes table
1052 * @param nodeuid the inserted node uid
1053 * @param node the node to insert
1055 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1058 add_node (unsigned long long *nodeuid, struct GNUNET_PeerIdentity * node)
1060 struct GNUNET_CRYPTO_HashAsciiEncoded encPeer;
1061 unsigned long p_len;
1062 unsigned long h_len;
1066 return GNUNET_SYSERR;
1068 GNUNET_CRYPTO_hash_to_enc (&node->hashPubKey, &encPeer);
1069 p_len = (unsigned long) strlen ((char *) &encPeer);
1070 h_len = sizeof (GNUNET_HashCode);
1072 (ret = prepared_statement_run (insert_node,
1074 MYSQL_TYPE_LONGLONG,
1077 MYSQL_TYPE_VAR_STRING,
1083 sizeof (GNUNET_HashCode),
1086 if (ret == GNUNET_SYSERR)
1088 return GNUNET_SYSERR;
1095 * Update dhttests.trials table with current server time as end time
1097 * @param trialuid trial to update
1098 * @param totalMessagesDropped stats value for messages dropped
1099 * @param totalBytesDropped stats value for total bytes dropped
1100 * @param unknownPeers stats value for unknown peers
1102 * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1105 update_trials (unsigned long long trialuid,
1106 unsigned long long totalMessagesDropped,
1107 unsigned long long totalBytesDropped,
1108 unsigned long long unknownPeers)
1113 (ret = prepared_statement_run (update_trial,
1115 MYSQL_TYPE_LONGLONG,
1116 &totalMessagesDropped,
1118 MYSQL_TYPE_LONGLONG,
1121 MYSQL_TYPE_LONGLONG,
1124 MYSQL_TYPE_LONGLONG,
1125 &trialuid, GNUNET_YES, -1)))
1127 if (ret == GNUNET_SYSERR)
1129 return GNUNET_SYSERR;
1135 return GNUNET_SYSERR;
1140 * Update dhttests.trials table with total connections information
1142 * @param trialuid the trialuid to update
1143 * @param totalConnections the number of connections
1145 * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1148 add_connections (unsigned long long trialuid, unsigned int totalConnections)
1153 (ret = prepared_statement_run (update_connection,
1158 MYSQL_TYPE_LONGLONG,
1159 &trialuid, GNUNET_YES, -1)))
1161 if (ret == GNUNET_SYSERR)
1163 return GNUNET_SYSERR;
1169 return GNUNET_SYSERR;
1173 * Inserts the specified query into the dhttests.queries table
1175 * @param sqlqueruid inserted query uid
1176 * @param queryid dht query id
1177 * @param type type of the query
1178 * @param hops number of hops query traveled
1179 * @param succeeded whether or not query was successful
1180 * @param node the node the query hit
1181 * @param key the key of the query
1183 * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1186 add_query (unsigned long long *sqlqueryuid, unsigned long long queryid,
1187 unsigned int type, unsigned int hops, int succeeded,
1188 const struct GNUNET_PeerIdentity * node, const GNUNET_HashCode * key)
1191 unsigned long long peer_uid, key_uid;
1196 && (GNUNET_OK == get_node_uid (&peer_uid, &node->hashPubKey)))
1202 return GNUNET_SYSERR;
1205 if ((key != NULL) && (GNUNET_OK == get_dhtkey_uid (&key_uid, key)))
1209 else if ((key != NULL) && (key->bits[(512 / 8 / sizeof (unsigned int)) - 1] == 42)) /* Malicious marker */
1215 return GNUNET_SYSERR;
1219 (ret = prepared_statement_run (insert_query,
1221 MYSQL_TYPE_LONGLONG,
1230 MYSQL_TYPE_LONGLONG,
1233 MYSQL_TYPE_LONGLONG,
1239 MYSQL_TYPE_LONGLONG,
1240 &peer_uid, GNUNET_YES, -1)))
1242 if (ret == GNUNET_SYSERR)
1244 return GNUNET_SYSERR;
1250 return GNUNET_SYSERR;
1254 * Inserts the specified route information into the dhttests.routes table
1256 * @param sqlqueruid inserted query uid
1257 * @param queryid dht query id
1258 * @param type type of the query
1259 * @param hops number of hops query traveled
1260 * @param succeeded whether or not query was successful
1261 * @param node the node the query hit
1262 * @param key the key of the query
1263 * @param from_node the node that sent the message to node
1264 * @param to_node next node to forward message to
1266 * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1269 add_route (unsigned long long *sqlqueryuid, unsigned long long queryid,
1270 unsigned int type, unsigned int hops,
1271 int succeeded, const struct GNUNET_PeerIdentity * node,
1272 const GNUNET_HashCode * key, const struct GNUNET_PeerIdentity * from_node,
1273 const struct GNUNET_PeerIdentity * to_node)
1275 unsigned long long peer_uid = 0;
1276 unsigned long long key_uid = 0;
1277 unsigned long long from_uid = 0;
1278 unsigned long long to_uid = 0;
1281 if (from_node != NULL)
1282 get_node_uid (&from_uid, &from_node->hashPubKey);
1286 if (to_node != NULL)
1287 get_node_uid (&to_uid, &to_node->hashPubKey);
1293 if (1 != get_node_uid (&peer_uid, &node->hashPubKey))
1295 return GNUNET_SYSERR;
1299 return GNUNET_SYSERR;
1303 if (1 != get_dhtkey_uid (&key_uid, key))
1305 return GNUNET_SYSERR;
1309 return GNUNET_SYSERR;
1312 (ret = prepared_statement_run (insert_route,
1314 MYSQL_TYPE_LONGLONG,
1323 MYSQL_TYPE_LONGLONG,
1326 MYSQL_TYPE_LONGLONG,
1332 MYSQL_TYPE_LONGLONG,
1335 MYSQL_TYPE_LONGLONG,
1338 MYSQL_TYPE_LONGLONG,
1339 &to_uid, GNUNET_YES, -1)))
1341 if (ret == GNUNET_SYSERR)
1343 return GNUNET_SYSERR;
1349 return GNUNET_SYSERR;
1353 * Update dhttests.topology table with total connections information
1355 * @param totalConnections the number of connections
1357 * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1360 update_current_topology (unsigned int connections)
1363 unsigned long long topologyuid;
1365 get_current_topology(&topologyuid);
1368 (ret = prepared_statement_run (update_topology,
1373 MYSQL_TYPE_LONGLONG,
1374 &topologyuid, GNUNET_YES, -1)))
1376 if (ret == GNUNET_SYSERR)
1378 return GNUNET_SYSERR;
1384 return GNUNET_SYSERR;
1389 * Records the current topology (number of connections, time, trial)
1391 * @param num_connections how many connections are in the topology
1393 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1396 add_topology (int num_connections)
1401 (ret = prepared_statement_run (insert_topology,
1403 MYSQL_TYPE_LONGLONG,
1410 if (ret == GNUNET_SYSERR)
1412 return GNUNET_SYSERR;
1418 return GNUNET_SYSERR;
1423 * Records a connection between two peers in the current topology
1425 * @param first one side of the connection
1426 * @param second other side of the connection
1428 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1431 add_extended_topology (const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second)
1434 unsigned long long first_uid;
1435 unsigned long long second_uid;
1436 unsigned long long topologyuid;
1438 if (GNUNET_OK != get_current_topology(&topologyuid))
1439 return GNUNET_SYSERR;
1440 if (GNUNET_OK != get_node_uid(&first_uid, &first->hashPubKey))
1441 return GNUNET_SYSERR;
1442 if (GNUNET_OK != get_node_uid(&second_uid, &second->hashPubKey))
1443 return GNUNET_SYSERR;
1446 (ret = prepared_statement_run (extend_topology,
1448 MYSQL_TYPE_LONGLONG,
1451 MYSQL_TYPE_LONGLONG,
1454 MYSQL_TYPE_LONGLONG,
1458 if (ret == GNUNET_SYSERR)
1460 return GNUNET_SYSERR;
1466 return GNUNET_SYSERR;
1472 * Provides the dhtlog api
1474 * @param c the configuration to use to connect to a server
1476 * @return the handle to the server, or NULL on error
1479 libgnunet_plugin_dhtlog_mysql_init (void * cls)
1481 struct GNUNET_DHTLOG_Plugin *plugin = cls;
1484 max_varchar_len = 255;
1486 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MySQL DHT Logger: initializing database\n");
1489 if (iopen (plugin) != GNUNET_OK)
1491 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1492 _("Failed to initialize MySQL database connection for dhtlog.\n"));
1496 GNUNET_assert(plugin->dhtlog_api == NULL);
1497 plugin->dhtlog_api = GNUNET_malloc(sizeof(struct GNUNET_DHTLOG_Handle));
1498 plugin->dhtlog_api->insert_trial = &add_trial;
1499 plugin->dhtlog_api->insert_stat = &add_stat;
1500 plugin->dhtlog_api->insert_query = &add_query;
1501 plugin->dhtlog_api->update_trial = &update_trials;
1502 plugin->dhtlog_api->insert_route = &add_route;
1503 plugin->dhtlog_api->insert_node = &add_node;
1504 plugin->dhtlog_api->insert_dhtkey = &add_dhtkey;
1505 plugin->dhtlog_api->update_connections = &add_connections;
1506 plugin->dhtlog_api->insert_topology = &add_topology;
1507 plugin->dhtlog_api->update_topology = &update_current_topology;
1508 plugin->dhtlog_api->insert_extended_topology = &add_extended_topology;
1509 get_current_trial (¤t_trial);
1515 * Shutdown the plugin.
1518 libgnunet_plugin_dhtlog_mysql_done (void * cls)
1520 struct GNUNET_DHTLOG_Handle *dhtlog_api = cls;
1522 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1523 "MySQL DHT Logger: database shutdown\n");
1524 GNUNET_assert(dhtlog_api != NULL);
1525 prepared_statement_close(insert_query);
1526 prepared_statement_close(insert_route);
1527 prepared_statement_close(insert_trial);
1528 prepared_statement_close(insert_node);
1529 prepared_statement_close(insert_dhtkey);
1530 prepared_statement_close(update_trial);
1531 prepared_statement_close(get_dhtkeyuid);
1532 prepared_statement_close(get_nodeuid);
1533 prepared_statement_close(update_connection);
1534 prepared_statement_close(get_trial);
1535 prepared_statement_close(get_topology);
1536 prepared_statement_close(insert_topology);
1537 prepared_statement_close(update_topology);
1538 prepared_statement_close(extend_topology);
1543 mysql_library_end();
1544 GNUNET_free(dhtlog_api);
1548 /* end of plugin_dhtlog_mysql.c */