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, 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_DHTKEY_STMT "INSERT INTO dhtkeys (dhtkey, trialuid, keybits) "\
132 static struct StatementHandle *insert_dhtkey;
134 #define UPDATE_TRIALS_STMT "UPDATE trials set endtime=NOW(), gets_succeeded = ? where trialuid = ?"
135 static struct StatementHandle *update_trial;
137 #define UPDATE_CONNECTIONS_STMT "UPDATE trials set totalConnections = ? where trialuid = ?"
138 static struct StatementHandle *update_connection;
140 #define GET_TRIAL_STMT "SELECT MAX( trialuid ) FROM trials"
141 static struct StatementHandle *get_trial;
143 #define GET_TOPOLOGY_STMT "SELECT MAX( topology_uid ) FROM topology"
144 static struct StatementHandle *get_topology;
146 #define GET_DHTKEYUID_STMT "SELECT dhtkeyuid FROM dhtkeys where dhtkey = ? and trialuid = ?"
147 static struct StatementHandle *get_dhtkeyuid;
149 #define GET_NODEUID_STMT "SELECT nodeuid FROM nodes where trialuid = ? and nodeid = ?"
150 static struct StatementHandle *get_nodeuid;
152 #define INSERT_TOPOLOGY_STMT "INSERT INTO topology (trialuid, date, connections) "\
153 "VALUES (?, NOW(), ?)"
154 static struct StatementHandle *insert_topology;
156 #define EXTEND_TOPOLOGY_STMT "INSERT INTO extended_topology (topology_uid, uid_first, uid_second) "\
158 static struct StatementHandle *extend_topology;
160 #define UPDATE_TOPOLOGY_STMT "update topology set connections = ? where topology_uid = ?"
161 static struct StatementHandle *update_topology;
164 * Run a query (not a select statement)
166 * @return GNUNET_OK if executed, GNUNET_SYSERR if an error occurred
169 run_statement (const char *statement)
171 mysql_query (conn, statement);
172 if (mysql_error (conn)[0])
174 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
176 return GNUNET_SYSERR;
182 * Creates tables if they don't already exist for dht logging
187 #define MRUNS(a) (GNUNET_OK != run_statement (a) )
189 if (MRUNS ("CREATE TABLE IF NOT EXISTS `dhtkeys` ("
190 "dhtkeyuid int(10) unsigned NOT NULL auto_increment COMMENT 'Unique Key given to each query',"
191 "`dhtkey` varchar(255) NOT NULL COMMENT 'The ASCII value of the key being searched for',"
192 "trialuid int(10) unsigned NOT NULL,"
193 "keybits blob NOT NULL,"
194 "UNIQUE KEY `dhtkeyuid` (`dhtkeyuid`)"
195 ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1"))
196 return GNUNET_SYSERR;
198 if (MRUNS ("CREATE TABLE IF NOT EXISTS `nodes` ("
199 "`nodeuid` int(10) unsigned NOT NULL auto_increment,"
200 "`trialuid` int(10) unsigned NOT NULL,"
201 "`nodeid` varchar(255) NOT NULL,"
202 "`nodebits` blob NOT NULL,"
203 "PRIMARY KEY (`nodeuid`)"
204 ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1"))
205 return GNUNET_SYSERR;
207 if (MRUNS ("CREATE TABLE IF NOT EXISTS `queries` ("
208 "`trialuid` int(10) unsigned NOT NULL,"
209 "`queryuid` int(10) unsigned NOT NULL auto_increment,"
210 "`dhtqueryid` bigint(20) NOT NULL,"
211 "`querytype` enum('1','2','3','4','5') NOT NULL,"
212 "`hops` int(10) unsigned NOT NULL,"
213 "`succeeded` tinyint NOT NULL,"
214 "`nodeuid` int(10) unsigned NOT NULL,"
215 "`time` timestamp NOT NULL default CURRENT_TIMESTAMP,"
216 "`dhtkeyuid` int(10) unsigned NOT NULL,"
217 "PRIMARY KEY (`queryuid`)"
218 ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1"))
219 return GNUNET_SYSERR;
221 if (MRUNS ("CREATE TABLE IF NOT EXISTS `routes` ("
222 "`trialuid` int(10) unsigned NOT NULL,"
223 "`queryuid` int(10) unsigned NOT NULL auto_increment,"
224 "`dhtqueryid` bigint(20) NOT NULL,"
225 "`querytype` enum('1','2','3','4','5') NOT NULL,"
226 "`hops` int(10) unsigned NOT NULL,"
227 "`succeeded` tinyint NOT NULL,"
228 "`nodeuid` int(10) unsigned NOT NULL,"
229 "`time` timestamp NOT NULL default CURRENT_TIMESTAMP,"
230 "`dhtkeyuid` int(10) unsigned NOT NULL,"
231 "`from_node` int(10) unsigned NOT NULL,"
232 "`to_node` int(10) unsigned NOT NULL,"
233 "PRIMARY KEY (`queryuid`)"
234 ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1"))
235 return GNUNET_SYSERR;
237 if (MRUNS ("CREATE TABLE IF NOT EXISTS `trials` ("
238 "`trialuid` int(10) unsigned NOT NULL auto_increment,"
239 "`numnodes` int(10) unsigned NOT NULL,"
240 "`topology` int(10) NOT NULL,"
241 "`starttime` datetime NOT NULL,"
242 "`endtime` datetime NOT NULL,"
243 "`puts` int(10) unsigned NOT NULL,"
244 "`gets` int(10) unsigned NOT NULL,"
245 "`concurrent` int(10) unsigned NOT NULL,"
246 "`settle_time` int(10) unsigned NOT NULL,"
247 "`totalConnections` int(10) unsigned NOT NULL,"
248 "`message` text NOT NULL,"
249 "`num_rounds` int(10) unsigned NOT NULL,"
250 "`malicious_getters` int(10) unsigned NOT NULL,"
251 "`malicious_putters` int(10) unsigned NOT NULL,"
252 "`malicious_droppers` int(10) unsigned NOT NULL,"
253 "`totalMessagesDropped` int(10) unsigned NOT NULL,"
254 "`totalBytesDropped` int(10) unsigned NOT NULL,"
255 "`topology_modifier` double NOT NULL,"
256 "`logNMultiplier` double NOT NULL,"
257 "`maxnetbps` bigint(20) unsigned NOT NULL,"
258 "`unknownPeers` int(10) unsigned NOT NULL,"
259 "PRIMARY KEY (`trialuid`),"
260 "UNIQUE KEY `trialuid` (`trialuid`)"
261 ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1"))
262 return GNUNET_SYSERR;
264 if (MRUNS ("CREATE TABLE IF NOT EXISTS `topology` ("
265 "`topology_uid` int(10) unsigned NOT NULL AUTO_INCREMENT,"
266 "`trialuid` int(10) unsigned NOT NULL,"
267 "`date` datetime NOT NULL,"
268 "`connections` int(10) unsigned NOT NULL,"
269 "PRIMARY KEY (`topology_uid`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1"))
270 return GNUNET_SYSERR;
272 if (MRUNS ("CREATE TABLE IF NOT EXISTS `extended_topology` ("
273 "`extended_uid` int(10) unsigned NOT NULL AUTO_INCREMENT,"
274 "`topology_uid` int(10) unsigned NOT NULL,"
275 "`uid_first` int(10) unsigned NOT NULL,"
276 "`uid_second` int(10) unsigned NOT NULL,"
277 "PRIMARY KEY (`extended_uid`)"
278 ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1"))
279 return GNUNET_SYSERR;
281 if (MRUNS ("CREATE TABLE IF NOT EXISTS `node_statistics` ("
282 "`stat_uid` int(10) unsigned NOT NULL AUTO_INCREMENT,"
283 "`trialuid` int(10) unsigned NOT NULL,"
284 "`nodeuid` int(10) unsigned NOT NULL,"
285 "`route_requests` int(10) unsigned NOT NULL,"
286 "`route_forwards` int(10) unsigned NOT NULL,"
287 "`result_requests` int(10) unsigned NOT NULL,"
288 "`client_results` int(10) unsigned NOT NULL,"
289 "`result_forwards` int(10) unsigned NOT NULL,"
290 "`gets` int(10) unsigned NOT NULL,"
291 "`puts` int(10) unsigned NOT NULL,"
292 "`data_inserts` int(10) unsigned NOT NULL,"
293 "`find_peer_requests` int(10) unsigned NOT NULL,"
294 "`find_peers_started` int(10) unsigned NOT NULL,"
295 "`gets_started` int(10) unsigned NOT NULL,"
296 "`puts_started` int(10) unsigned NOT NULL,"
297 "`find_peer_responses_received` int(10) unsigned NOT NULL,"
298 "`get_responses_received` int(10) unsigned NOT NULL,"
299 "`find_peer_responses_sent` int(10) unsigned NOT NULL,"
300 "`get_responses_sent` int(10) unsigned NOT NULL,"
301 "PRIMARY KEY (`stat_uid`)"
302 ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;"))
303 return GNUNET_SYSERR;
305 if (MRUNS ("SET AUTOCOMMIT = 1"))
306 return GNUNET_SYSERR;
313 * Create a prepared statement.
315 * @return NULL on error
317 struct StatementHandle *
318 prepared_statement_create (const char *statement)
320 struct StatementHandle *ret;
322 ret = GNUNET_malloc (sizeof (struct StatementHandle));
323 ret->query = GNUNET_strdup (statement);
328 * Close a prepared statement.
330 * @return NULL on error
333 prepared_statement_close (struct StatementHandle *s)
340 GNUNET_free_non_null(s->query);
342 if (s->valid == GNUNET_YES)
343 mysql_stmt_close(s->statement);
348 * Initialize the prepared statements for use with dht test logging
351 iopen (struct GNUNET_DHTLOG_Plugin *plugin)
355 unsigned int timeout;
360 unsigned long long port;
362 conn = mysql_init (NULL);
364 return GNUNET_SYSERR;
366 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (plugin->cfg,
370 database = GNUNET_strdup("gnunet");
373 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (plugin->cfg,
374 "MYSQL", "USER", &user))
376 user = GNUNET_strdup("dht");
379 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (plugin->cfg,
380 "MYSQL", "PASSWORD", &password))
382 password = GNUNET_strdup("dhttest**");
385 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (plugin->cfg,
386 "MYSQL", "SERVER", &server))
388 server = GNUNET_strdup("localhost");
391 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (plugin->cfg,
392 "MYSQL", "MYSQL_PORT", &port))
397 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to mysql with: user %s, pass %s, server %s, database %s, port %d\n",
398 user, password, server, database, port);
401 timeout = 60; /* in seconds */
402 mysql_options (conn, MYSQL_OPT_RECONNECT, &reconnect);
404 MYSQL_OPT_CONNECT_TIMEOUT, (const void *) &timeout);
405 mysql_options(conn, MYSQL_SET_CHARSET_NAME, "UTF8");
406 mysql_options (conn, MYSQL_OPT_READ_TIMEOUT, (const void *) &timeout);
407 mysql_options (conn, MYSQL_OPT_WRITE_TIMEOUT, (const void *) &timeout);
408 mysql_real_connect (conn, server, user, password,
409 database, (unsigned int) port, NULL, CLIENT_IGNORE_SIGPIPE);
411 GNUNET_free_non_null(server);
412 GNUNET_free_non_null(password);
413 GNUNET_free_non_null(user);
414 GNUNET_free_non_null(database);
416 if (mysql_error (conn)[0])
418 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
419 "mysql_real_connect");
420 return GNUNET_SYSERR;
424 db = GNUNET_MYSQL_database_open (coreAPI->ectx, coreAPI->cfg);
426 return GNUNET_SYSERR;
431 #define PINIT(a,b) (NULL == (a = prepared_statement_create(b)))
432 if (PINIT (insert_query, INSERT_QUERIES_STMT) ||
433 PINIT (insert_route, INSERT_ROUTES_STMT) ||
434 PINIT (insert_trial, INSERT_TRIALS_STMT) ||
435 PINIT (insert_stat, INSERT_STAT_STMT) ||
436 PINIT (insert_node, INSERT_NODES_STMT) ||
437 PINIT (insert_dhtkey, INSERT_DHTKEY_STMT) ||
438 PINIT (update_trial, UPDATE_TRIALS_STMT) ||
439 PINIT (get_dhtkeyuid, GET_DHTKEYUID_STMT) ||
440 PINIT (get_nodeuid, GET_NODEUID_STMT) ||
441 PINIT (update_connection, UPDATE_CONNECTIONS_STMT) ||
442 PINIT (get_trial, GET_TRIAL_STMT) ||
443 PINIT (get_topology, GET_TOPOLOGY_STMT) ||
444 PINIT (insert_topology, INSERT_TOPOLOGY_STMT)||
445 PINIT (update_topology, UPDATE_TOPOLOGY_STMT)||
446 PINIT (extend_topology, EXTEND_TOPOLOGY_STMT))
448 return GNUNET_SYSERR;
456 return_ok (void *cls, unsigned int num_values, MYSQL_BIND * values)
462 * Prepare a statement for running.
464 * @return GNUNET_OK on success
467 prepare_statement (struct StatementHandle *ret)
469 if (GNUNET_YES == ret->valid)
472 ret->statement = mysql_stmt_init (conn);
473 if (ret->statement == NULL)
474 return GNUNET_SYSERR;
476 if (mysql_stmt_prepare (ret->statement, ret->query, strlen (ret->query)))
478 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
479 "mysql_stmt_prepare `%s', %s", ret->query, mysql_error(conn));
480 mysql_stmt_close (ret->statement);
481 ret->statement = NULL;
482 return GNUNET_SYSERR;
484 ret->valid = GNUNET_YES;
489 * Bind the parameters for the given MySQL statement
492 * @param s statement to bind and run
493 * @param ap arguments for the binding
494 * @return GNUNET_SYSERR on error, GNUNET_OK on success
497 init_params (struct StatementHandle *s, va_list ap)
499 MYSQL_BIND qbind[MAX_PARAM];
502 enum enum_field_types ft;
504 pc = mysql_stmt_param_count (s->statement);
507 /* increase internal constant! */
509 return GNUNET_SYSERR;
511 memset (qbind, 0, sizeof (qbind));
514 while ((pc > 0) && (-1 != (ft = va_arg (ap, enum enum_field_types))))
516 qbind[off].buffer_type = ft;
519 case MYSQL_TYPE_FLOAT:
520 qbind[off].buffer = va_arg (ap, float *);
522 case MYSQL_TYPE_LONGLONG:
523 qbind[off].buffer = va_arg (ap, unsigned long long *);
524 qbind[off].is_unsigned = va_arg (ap, int);
526 case MYSQL_TYPE_LONG:
527 qbind[off].buffer = va_arg (ap, unsigned int *);
528 qbind[off].is_unsigned = va_arg (ap, int);
530 case MYSQL_TYPE_VAR_STRING:
531 case MYSQL_TYPE_STRING:
532 case MYSQL_TYPE_BLOB:
533 qbind[off].buffer = va_arg (ap, void *);
534 qbind[off].buffer_length = va_arg (ap, unsigned long);
535 qbind[off].length = va_arg (ap, unsigned long *);
538 /* unsupported type */
540 return GNUNET_SYSERR;
545 if (!((pc == 0) && (ft != -1) && (va_arg (ap, int) == -1)))
548 return GNUNET_SYSERR;
550 if (mysql_stmt_bind_param (s->statement, qbind))
552 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
553 _("`%s' failed at %s:%d with error: %s\n"),
554 "mysql_stmt_bind_param",
555 __FILE__, __LINE__, mysql_stmt_error (s->statement));
556 return GNUNET_SYSERR;
559 if (mysql_stmt_execute (s->statement))
561 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
562 _("`%s' failed at %s:%d with error: %s\n"),
563 "mysql_stmt_execute",
564 __FILE__, __LINE__, mysql_stmt_error (s->statement));
565 return GNUNET_SYSERR;
572 * Run a prepared SELECT statement.
574 * @param result_size number of elements in results array
575 * @param results pointer to already initialized MYSQL_BIND
576 * array (of sufficient size) for passing results
577 * @param processor function to call on each result
578 * @param processor_cls extra argument to processor
579 * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective
580 * values (size + buffer-reference for pointers); terminated
582 * @return GNUNET_SYSERR on error, otherwise
583 * the number of successfully affected (or queried) rows
586 prepared_statement_run_select (struct StatementHandle
587 *s, unsigned int result_size,
588 MYSQL_BIND * results,
589 GNUNET_MysqlDataProcessor
590 processor, void *processor_cls,
598 if (GNUNET_OK != prepare_statement (s))
601 return GNUNET_SYSERR;
603 va_start (ap, processor_cls);
604 if (GNUNET_OK != init_params (s, ap))
608 return GNUNET_SYSERR;
611 rsize = mysql_stmt_field_count (s->statement);
612 if (rsize > result_size)
615 return GNUNET_SYSERR;
617 if (mysql_stmt_bind_result (s->statement, results))
619 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
620 _("`%s' failed at %s:%d with error: %s\n"),
621 "mysql_stmt_bind_result",
622 __FILE__, __LINE__, mysql_stmt_error (s->statement));
623 return GNUNET_SYSERR;
629 ret = mysql_stmt_fetch (s->statement);
630 if (ret == MYSQL_NO_DATA)
634 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
635 _("`%s' failed at %s:%d with error: %s\n"),
637 __FILE__, __LINE__, mysql_stmt_error (s->statement));
638 return GNUNET_SYSERR;
640 if (processor != NULL)
641 if (GNUNET_OK != processor (processor_cls, rsize, results))
645 mysql_stmt_reset (s->statement);
651 get_node_uid (unsigned long long *nodeuid, const GNUNET_HashCode * peerHash)
654 struct GNUNET_CRYPTO_HashAsciiEncoded encPeer;
655 unsigned long long p_len;
658 memset (rbind, 0, sizeof (rbind));
659 rbind[0].buffer_type = MYSQL_TYPE_LONGLONG;
660 rbind[0].buffer = nodeuid;
661 rbind[0].is_unsigned = GNUNET_YES;
663 GNUNET_CRYPTO_hash_to_enc (peerHash, &encPeer);
664 p_len = strlen ((char *) &encPeer);
666 if (1 != (ret = prepared_statement_run_select (get_nodeuid,
674 MYSQL_TYPE_VAR_STRING,
680 fprintf (stderr, "FAILED\n");
682 return GNUNET_SYSERR;
688 get_current_trial (unsigned long long *trialuid)
692 memset (rbind, 0, sizeof (rbind));
693 rbind[0].buffer_type = MYSQL_TYPE_LONG;
694 rbind[0].is_unsigned = 1;
695 rbind[0].buffer = trialuid;
698 prepared_statement_run_select (get_trial,
701 return_ok, NULL, -1)))
703 return GNUNET_SYSERR;
710 get_current_topology (unsigned long long *topologyuid)
714 memset (rbind, 0, sizeof (rbind));
715 rbind[0].buffer_type = MYSQL_TYPE_LONGLONG;
716 rbind[0].is_unsigned = 1;
717 rbind[0].buffer = topologyuid;
720 prepared_statement_run_select (get_topology,
723 return_ok, NULL, -1)))
725 return GNUNET_SYSERR;
732 get_dhtkey_uid (unsigned long long *dhtkeyuid, const GNUNET_HashCode * key)
735 struct GNUNET_CRYPTO_HashAsciiEncoded encKey;
736 unsigned long long k_len;
737 memset (rbind, 0, sizeof (rbind));
738 rbind[0].buffer_type = MYSQL_TYPE_LONG;
739 rbind[0].is_unsigned = 1;
740 rbind[0].buffer = dhtkeyuid;
741 GNUNET_CRYPTO_hash_to_enc (key, &encKey);
742 k_len = strlen ((char *) &encKey);
745 prepared_statement_run_select (get_dhtkeyuid,
749 MYSQL_TYPE_VAR_STRING,
757 return GNUNET_SYSERR;
764 * Run a prepared statement that does NOT produce results.
766 * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective
767 * values (size + buffer-reference for pointers); terminated
769 * @param insert_id NULL or address where to store the row ID of whatever
770 * was inserted (only for INSERT statements!)
771 * @return GNUNET_SYSERR on error, otherwise
772 * the number of successfully affected rows
775 prepared_statement_run (struct StatementHandle *s,
776 unsigned long long *insert_id, ...)
781 if (GNUNET_OK != prepare_statement(s))
784 return GNUNET_SYSERR;
786 GNUNET_assert(s->valid == GNUNET_YES);
787 if (s->statement == NULL)
788 return GNUNET_SYSERR;
790 va_start (ap, insert_id);
792 if (GNUNET_OK != init_params (s, ap))
795 return GNUNET_SYSERR;
799 affected = mysql_stmt_affected_rows (s->statement);
800 if (NULL != insert_id)
801 *insert_id = (unsigned long long) mysql_stmt_insert_id (s->statement);
802 mysql_stmt_reset (s->statement);
808 * Inserts the specified trial into the dhttests.trials table
810 * @param trialuid return the trialuid of the newly inserted trial
811 * @param num_nodes how many nodes are in the trial
812 * @param topology integer representing topology for this trial
813 * @param blacklist_topology integer representing blacklist topology for this trial
814 * @param connect_topology integer representing connect topology for this trial
815 * @param connect_topology_option integer representing connect topology option
816 * @param connect_topology_option_modifier float to modify connect option
817 * @param topology_percentage percentage modifier for certain topologies
818 * @param topology_probability probability modifier for certain topologies
819 * @param puts number of puts to perform
820 * @param gets number of gets to perform
821 * @param concurrent number of concurrent requests
822 * @param settle_time time to wait between creating topology and starting testing
823 * @param num_rounds number of times to repeat the trial
824 * @param malicious_getters number of malicious GET peers in the trial
825 * @param malicious_putters number of malicious PUT peers in the trial
826 * @param malicious_droppers number of malicious DROP peers in the trial
827 * @param malicious_get_frequency how often malicious gets are sent
828 * @param malicious_put_frequency how often malicious puts are sent
829 * @param stop_closest stop forwarding PUTs if closest node found
830 * @param stop_found stop forwarding GETs if data found
831 * @param strict_kademlia test used kademlia routing algorithm
832 * @param gets_succeeded how many gets did the test driver report success on
833 * @param message string to put into DB for this trial
835 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
837 int add_trial (unsigned long long *trialuid, unsigned int num_nodes, unsigned int topology,
838 unsigned int blacklist_topology, unsigned int connect_topology,
839 unsigned int connect_topology_option, float connect_topology_option_modifier,
840 float topology_percentage, float topology_probability,
841 unsigned int puts, unsigned int gets, unsigned int concurrent, unsigned int settle_time,
842 unsigned int num_rounds, unsigned int malicious_getters, unsigned int malicious_putters,
843 unsigned int malicious_droppers, unsigned int malicious_get_frequency,
844 unsigned int malicious_put_frequency, unsigned int stop_closest, unsigned int stop_found,
845 unsigned int strict_kademlia, unsigned int gets_succeeded,
850 unsigned long long m_len;
851 m_len = strlen (message);
853 stmt = mysql_stmt_init(conn);
855 (ret = prepared_statement_run (insert_trial, trialuid,
856 MYSQL_TYPE_LONG, &num_nodes, GNUNET_YES,
857 MYSQL_TYPE_LONG, &topology, GNUNET_YES,
858 MYSQL_TYPE_FLOAT, &topology_percentage,
859 MYSQL_TYPE_FLOAT, &topology_probability,
860 MYSQL_TYPE_LONG, &blacklist_topology, GNUNET_YES,
861 MYSQL_TYPE_LONG, &connect_topology, GNUNET_YES,
862 MYSQL_TYPE_LONG, &connect_topology_option, GNUNET_YES,
863 MYSQL_TYPE_FLOAT, &connect_topology_option_modifier,
864 MYSQL_TYPE_LONG, &puts, GNUNET_YES,
865 MYSQL_TYPE_LONG, &gets, GNUNET_YES,
866 MYSQL_TYPE_LONG, &concurrent, GNUNET_YES,
867 MYSQL_TYPE_LONG, &settle_time, GNUNET_YES,
868 MYSQL_TYPE_LONG, &num_rounds, GNUNET_YES,
869 MYSQL_TYPE_LONG, &malicious_getters, GNUNET_YES,
870 MYSQL_TYPE_LONG, &malicious_putters, GNUNET_YES,
871 MYSQL_TYPE_LONG, &malicious_droppers, GNUNET_YES,
872 MYSQL_TYPE_LONG, &malicious_get_frequency, GNUNET_YES,
873 MYSQL_TYPE_LONG, &malicious_put_frequency, GNUNET_YES,
874 MYSQL_TYPE_LONG, &stop_closest, GNUNET_YES,
875 MYSQL_TYPE_LONG, &stop_found, GNUNET_YES,
876 MYSQL_TYPE_LONG, &strict_kademlia, GNUNET_YES,
877 MYSQL_TYPE_LONG, &gets_succeeded, GNUNET_YES,
878 MYSQL_TYPE_BLOB, message, max_varchar_len +
879 max_varchar_len, &m_len,
882 if (ret == GNUNET_SYSERR)
884 mysql_stmt_close(stmt);
885 return GNUNET_SYSERR;
889 get_current_trial (¤t_trial);
891 mysql_stmt_close(stmt);
897 * Inserts the specified stats into the dhttests.node_statistics table
899 * @param peer the peer inserting the statistic
900 * @param route_requests route requests seen
901 * @param route_forwards route requests forwarded
902 * @param result_requests route result requests seen
903 * @param client_requests client requests initiated
904 * @param result_forwards route results forwarded
905 * @param gets get requests handled
906 * @param puts put requests handle
907 * @param data_inserts data inserted at this node
908 * @param find_peer_requests find peer requests seen
909 * @param find_peers_started find peer requests initiated at this node
910 * @param gets_started get requests initiated at this node
911 * @param puts_started put requests initiated at this node
912 * @param find_peer_responses_received find peer responses received locally
913 * @param get_responses_received get responses received locally
914 * @param find_peer_responses_sent find peer responses sent from this node
915 * @param get_responses_sent get responses sent from this node
917 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
920 add_stat (const struct GNUNET_PeerIdentity *peer, unsigned int route_requests,
921 unsigned int route_forwards, unsigned int result_requests,
922 unsigned int client_requests, unsigned int result_forwards,
923 unsigned int gets, unsigned int puts,
924 unsigned int data_inserts, unsigned int find_peer_requests,
925 unsigned int find_peers_started, unsigned int gets_started,
926 unsigned int puts_started, unsigned int find_peer_responses_received,
927 unsigned int get_responses_received, unsigned int find_peer_responses_sent,
928 unsigned int get_responses_sent)
932 unsigned long long peer_uid;
933 unsigned long long return_uid;
935 return GNUNET_SYSERR;
937 if (GNUNET_OK != get_node_uid (&peer_uid, &peer->hashPubKey))
939 return GNUNET_SYSERR;
942 stmt = mysql_stmt_init(conn);
944 (ret = prepared_statement_run (insert_stat,
946 MYSQL_TYPE_LONGLONG, ¤t_trial, GNUNET_YES,
947 MYSQL_TYPE_LONGLONG, &peer_uid, GNUNET_YES,
948 MYSQL_TYPE_LONG, &route_requests, GNUNET_YES,
949 MYSQL_TYPE_LONG, &route_forwards, GNUNET_YES,
950 MYSQL_TYPE_LONG, &result_requests, GNUNET_YES,
951 MYSQL_TYPE_LONG, &client_requests, GNUNET_YES,
952 MYSQL_TYPE_LONG, &result_forwards, GNUNET_YES,
953 MYSQL_TYPE_LONG, &gets, GNUNET_YES,
954 MYSQL_TYPE_LONG, &puts, GNUNET_YES,
955 MYSQL_TYPE_LONG, &data_inserts, GNUNET_YES,
956 MYSQL_TYPE_LONG, &find_peer_requests, GNUNET_YES,
957 MYSQL_TYPE_LONG, &find_peers_started, GNUNET_YES,
958 MYSQL_TYPE_LONG, &gets_started, GNUNET_YES,
959 MYSQL_TYPE_LONG, &puts_started, GNUNET_YES,
960 MYSQL_TYPE_LONG, &find_peer_responses_received, GNUNET_YES,
961 MYSQL_TYPE_LONG, &get_responses_received, GNUNET_YES,
962 MYSQL_TYPE_LONG, &find_peer_responses_sent, GNUNET_YES,
963 MYSQL_TYPE_LONG, &get_responses_sent, GNUNET_YES,
966 if (ret == GNUNET_SYSERR)
968 mysql_stmt_close(stmt);
969 return GNUNET_SYSERR;
973 mysql_stmt_close(stmt);
978 * Inserts the specified dhtkey into the dhttests.dhtkeys table,
979 * stores return value of dhttests.dhtkeys.dhtkeyuid into dhtkeyuid
981 * @param dhtkeyuid return value
982 * @param dhtkey hashcode of key to insert
984 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
987 add_dhtkey (unsigned long long *dhtkeyuid, const GNUNET_HashCode * dhtkey)
991 struct GNUNET_CRYPTO_HashAsciiEncoded encKey;
992 unsigned long long k_len;
993 unsigned long long h_len;
994 unsigned long long curr_dhtkeyuid;
995 GNUNET_CRYPTO_hash_to_enc (dhtkey, &encKey);
996 k_len = strlen ((char *) &encKey);
997 h_len = sizeof (GNUNET_HashCode);
999 ret = get_dhtkey_uid(&curr_dhtkeyuid, dhtkey);
1000 if (curr_dhtkeyuid != 0) /* dhtkey already exists */
1002 if (dhtkeyuid != NULL)
1003 *dhtkeyuid = curr_dhtkeyuid;
1008 (ret = prepared_statement_run (insert_dhtkey,
1010 MYSQL_TYPE_VAR_STRING,
1019 sizeof (GNUNET_HashCode),
1022 if (ret == GNUNET_SYSERR)
1024 return GNUNET_SYSERR;
1034 * Inserts the specified node into the dhttests.nodes table
1036 * @param nodeuid the inserted node uid
1037 * @param node the node to insert
1039 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1042 add_node (unsigned long long *nodeuid, struct GNUNET_PeerIdentity * node)
1044 struct GNUNET_CRYPTO_HashAsciiEncoded encPeer;
1045 unsigned long p_len;
1046 unsigned long h_len;
1050 return GNUNET_SYSERR;
1052 GNUNET_CRYPTO_hash_to_enc (&node->hashPubKey, &encPeer);
1053 p_len = (unsigned long) strlen ((char *) &encPeer);
1054 h_len = sizeof (GNUNET_HashCode);
1056 (ret = prepared_statement_run (insert_node,
1058 MYSQL_TYPE_LONGLONG,
1061 MYSQL_TYPE_VAR_STRING,
1067 sizeof (GNUNET_HashCode),
1070 if (ret == GNUNET_SYSERR)
1072 return GNUNET_SYSERR;
1079 * Update dhttests.trials table with current server time as end time
1081 * @param trialuid trial to update
1082 * @param gets_succeeded how many gets did the testcase report as successful
1084 * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1087 update_trials (unsigned long long trialuid,
1088 unsigned int gets_succeeded)
1093 (ret = prepared_statement_run (update_trial,
1095 MYSQL_TYPE_LONG, &gets_succeeded, GNUNET_YES,
1096 MYSQL_TYPE_LONGLONG, &trialuid, GNUNET_YES,
1099 if (ret == GNUNET_SYSERR)
1101 return GNUNET_SYSERR;
1107 return GNUNET_SYSERR;
1112 * Update dhttests.trials table with total connections information
1114 * @param trialuid the trialuid to update
1115 * @param totalConnections the number of connections
1117 * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1120 add_connections (unsigned long long trialuid, unsigned int totalConnections)
1125 (ret = prepared_statement_run (update_connection,
1130 MYSQL_TYPE_LONGLONG,
1131 &trialuid, GNUNET_YES, -1)))
1133 if (ret == GNUNET_SYSERR)
1135 return GNUNET_SYSERR;
1141 return GNUNET_SYSERR;
1145 * Inserts the specified query into the dhttests.queries table
1147 * @param sqlqueruid inserted query uid
1148 * @param queryid dht query id
1149 * @param type type of the query
1150 * @param hops number of hops query traveled
1151 * @param succeeded whether or not query was successful
1152 * @param node the node the query hit
1153 * @param key the key of the query
1155 * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1158 add_query (unsigned long long *sqlqueryuid, unsigned long long queryid,
1159 unsigned int type, unsigned int hops, int succeeded,
1160 const struct GNUNET_PeerIdentity * node, const GNUNET_HashCode * key)
1163 unsigned long long peer_uid, key_uid;
1168 && (GNUNET_OK == get_node_uid (&peer_uid, &node->hashPubKey)))
1174 return GNUNET_SYSERR;
1177 if ((key != NULL) && (GNUNET_OK == get_dhtkey_uid (&key_uid, key)))
1181 else if ((key != NULL) && (key->bits[(512 / 8 / sizeof (unsigned int)) - 1] == 42)) /* Malicious marker */
1187 return GNUNET_SYSERR;
1191 (ret = prepared_statement_run (insert_query,
1193 MYSQL_TYPE_LONGLONG,
1202 MYSQL_TYPE_LONGLONG,
1205 MYSQL_TYPE_LONGLONG,
1211 MYSQL_TYPE_LONGLONG,
1212 &peer_uid, GNUNET_YES, -1)))
1214 if (ret == GNUNET_SYSERR)
1216 return GNUNET_SYSERR;
1222 return GNUNET_SYSERR;
1226 * Inserts the specified route information into the dhttests.routes table
1228 * @param sqlqueruid inserted query uid
1229 * @param queryid dht query id
1230 * @param type type of the query
1231 * @param hops number of hops query traveled
1232 * @param succeeded whether or not query was successful
1233 * @param node the node the query hit
1234 * @param key the key of the query
1235 * @param from_node the node that sent the message to node
1236 * @param to_node next node to forward message to
1238 * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1241 add_route (unsigned long long *sqlqueryuid, unsigned long long queryid,
1242 unsigned int type, unsigned int hops,
1243 int succeeded, const struct GNUNET_PeerIdentity * node,
1244 const GNUNET_HashCode * key, const struct GNUNET_PeerIdentity * from_node,
1245 const struct GNUNET_PeerIdentity * to_node)
1247 unsigned long long peer_uid = 0;
1248 unsigned long long key_uid = 0;
1249 unsigned long long from_uid = 0;
1250 unsigned long long to_uid = 0;
1253 if (from_node != NULL)
1254 get_node_uid (&from_uid, &from_node->hashPubKey);
1258 if (to_node != NULL)
1259 get_node_uid (&to_uid, &to_node->hashPubKey);
1265 if (1 != get_node_uid (&peer_uid, &node->hashPubKey))
1267 return GNUNET_SYSERR;
1271 return GNUNET_SYSERR;
1275 if (1 != get_dhtkey_uid (&key_uid, key))
1277 return GNUNET_SYSERR;
1281 return GNUNET_SYSERR;
1284 (ret = prepared_statement_run (insert_route,
1286 MYSQL_TYPE_LONGLONG,
1295 MYSQL_TYPE_LONGLONG,
1298 MYSQL_TYPE_LONGLONG,
1304 MYSQL_TYPE_LONGLONG,
1307 MYSQL_TYPE_LONGLONG,
1310 MYSQL_TYPE_LONGLONG,
1311 &to_uid, GNUNET_YES, -1)))
1313 if (ret == GNUNET_SYSERR)
1315 return GNUNET_SYSERR;
1321 return GNUNET_SYSERR;
1325 * Update dhttests.topology table with total connections information
1327 * @param totalConnections the number of connections
1329 * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1332 update_current_topology (unsigned int connections)
1335 unsigned long long topologyuid;
1337 get_current_topology(&topologyuid);
1340 (ret = prepared_statement_run (update_topology,
1345 MYSQL_TYPE_LONGLONG,
1346 &topologyuid, GNUNET_YES, -1)))
1348 if (ret == GNUNET_SYSERR)
1350 return GNUNET_SYSERR;
1356 return GNUNET_SYSERR;
1361 * Records the current topology (number of connections, time, trial)
1363 * @param num_connections how many connections are in the topology
1365 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1368 add_topology (int num_connections)
1373 (ret = prepared_statement_run (insert_topology,
1375 MYSQL_TYPE_LONGLONG,
1382 if (ret == GNUNET_SYSERR)
1384 return GNUNET_SYSERR;
1390 return GNUNET_SYSERR;
1395 * Records a connection between two peers in the current topology
1397 * @param first one side of the connection
1398 * @param second other side of the connection
1400 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1403 add_extended_topology (const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second)
1406 unsigned long long first_uid;
1407 unsigned long long second_uid;
1408 unsigned long long topologyuid;
1410 if (GNUNET_OK != get_current_topology(&topologyuid))
1411 return GNUNET_SYSERR;
1412 if (GNUNET_OK != get_node_uid(&first_uid, &first->hashPubKey))
1413 return GNUNET_SYSERR;
1414 if (GNUNET_OK != get_node_uid(&second_uid, &second->hashPubKey))
1415 return GNUNET_SYSERR;
1418 (ret = prepared_statement_run (extend_topology,
1420 MYSQL_TYPE_LONGLONG,
1423 MYSQL_TYPE_LONGLONG,
1426 MYSQL_TYPE_LONGLONG,
1430 if (ret == GNUNET_SYSERR)
1432 return GNUNET_SYSERR;
1438 return GNUNET_SYSERR;
1444 * Provides the dhtlog api
1446 * @param c the configuration to use to connect to a server
1448 * @return the handle to the server, or NULL on error
1451 libgnunet_plugin_dhtlog_mysql_init (void * cls)
1453 struct GNUNET_DHTLOG_Plugin *plugin = cls;
1456 max_varchar_len = 255;
1458 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MySQL DHT Logger: initializing database\n");
1461 if (iopen (plugin) != GNUNET_OK)
1463 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1464 _("Failed to initialize MySQL database connection for dhtlog.\n"));
1468 GNUNET_assert(plugin->dhtlog_api == NULL);
1469 plugin->dhtlog_api = GNUNET_malloc(sizeof(struct GNUNET_DHTLOG_Handle));
1470 plugin->dhtlog_api->insert_trial = &add_trial;
1471 plugin->dhtlog_api->insert_stat = &add_stat;
1472 plugin->dhtlog_api->insert_query = &add_query;
1473 plugin->dhtlog_api->update_trial = &update_trials;
1474 plugin->dhtlog_api->insert_route = &add_route;
1475 plugin->dhtlog_api->insert_node = &add_node;
1476 plugin->dhtlog_api->insert_dhtkey = &add_dhtkey;
1477 plugin->dhtlog_api->update_connections = &add_connections;
1478 plugin->dhtlog_api->insert_topology = &add_topology;
1479 plugin->dhtlog_api->update_topology = &update_current_topology;
1480 plugin->dhtlog_api->insert_extended_topology = &add_extended_topology;
1481 get_current_trial (¤t_trial);
1487 * Shutdown the plugin.
1490 libgnunet_plugin_dhtlog_mysql_done (void * cls)
1492 struct GNUNET_DHTLOG_Handle *dhtlog_api = cls;
1494 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1495 "MySQL DHT Logger: database shutdown\n");
1496 GNUNET_assert(dhtlog_api != NULL);
1497 prepared_statement_close(insert_query);
1498 prepared_statement_close(insert_route);
1499 prepared_statement_close(insert_trial);
1500 prepared_statement_close(insert_node);
1501 prepared_statement_close(insert_dhtkey);
1502 prepared_statement_close(update_trial);
1503 prepared_statement_close(get_dhtkeyuid);
1504 prepared_statement_close(get_nodeuid);
1505 prepared_statement_close(update_connection);
1506 prepared_statement_close(get_trial);
1507 prepared_statement_close(get_topology);
1508 prepared_statement_close(insert_topology);
1509 prepared_statement_close(update_topology);
1510 prepared_statement_close(extend_topology);
1515 mysql_library_end();
1516 GNUNET_free(dhtlog_api);
1520 /* end of plugin_dhtlog_mysql.c */