dhtlog updates
[oweals/gnunet.git] / src / dht / plugin_dhtlog_mysql.c
1 /*
2      This file is part of GNUnet.
3      (C) 2006 - 2009 Christian Grothoff (and other contributing authors)
4
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.
9
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.
14
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.
19 */
20
21 /**
22  * @file src/dht/plugin_dhtlog_mysql.c
23  * @brief MySQL logging plugin to record DHT operations to MySQL server
24  * @author Nathan Evans
25  *
26  * Database: MySQL
27  */
28
29 #include "platform.h"
30 #include "gnunet_util_lib.h"
31 #include "dhtlog.h"
32 #include <mysql/mysql.h>
33
34
35 #define DEBUG_DHTLOG GNUNET_YES
36
37 /**
38  * Maximum number of supported parameters for a prepared
39  * statement.  Increase if needed.
40  */
41 #define MAX_PARAM 32
42
43 /**
44  * A generic statement handle to use
45  * for prepared statements.  This way,
46  * once the statement is initialized
47  * we don't redo work.
48  */
49 struct StatementHandle
50 {
51   /**
52    * Internal statement
53    */
54   MYSQL_STMT *statement;
55
56   /**
57    * Textual query
58    */
59   char *query;
60
61   /**
62    * Whether or not the handle is valid
63    */
64   int valid;
65 };
66
67 /**
68  * Type of a callback that will be called for each
69  * data set returned from MySQL.
70  *
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
75  */
76 typedef int (*GNUNET_MysqlDataProcessor) (void *cls,
77                                           unsigned int num_values,
78                                           MYSQL_BIND * values);
79
80 static unsigned long max_varchar_len;
81
82 /**
83  * The configuration the DHT service is running with
84  */
85 static const struct GNUNET_CONFIGURATION_Handle *cfg;
86
87 static unsigned long long current_trial = 0;    /* I like to assign 0, just to remember */
88
89 /**
90  * Connection to the MySQL Server.
91  */
92 static MYSQL *conn;
93
94 #define INSERT_QUERIES_STMT "INSERT INTO queries (trialuid, querytype, hops, dhtkeyuid, dhtqueryid, succeeded, nodeuid) "\
95                           "VALUES (?, ?, ?, ?, ?, ?, ?)"
96 static struct StatementHandle *insert_query;
97
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;
101
102 #define INSERT_NODES_STMT "INSERT INTO nodes (trialuid, nodeid, nodebits) "\
103                           "VALUES (?, ?, ?)"
104 static struct StatementHandle *insert_node;
105
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(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
116
117 static struct StatementHandle *insert_trial;
118
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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
127
128 static struct StatementHandle *insert_stat;
129
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;
134
135 #define INSERT_DHTKEY_STMT "INSERT INTO dhtkeys (dhtkey, trialuid, keybits) "\
136                           "VALUES (?, ?, ?)"
137 static struct StatementHandle *insert_dhtkey;
138
139 #define UPDATE_TRIALS_STMT "UPDATE trials set endtime=NOW(), gets_succeeded = ? where trialuid = ?"
140 static struct StatementHandle *update_trial;
141
142 #define UPDATE_CONNECTIONS_STMT "UPDATE trials set totalConnections = ? where trialuid = ?"
143 static struct StatementHandle *update_connection;
144
145 #define GET_TRIAL_STMT "SELECT MAX( trialuid ) FROM trials"
146 static struct StatementHandle *get_trial;
147
148 #define GET_TOPOLOGY_STMT "SELECT MAX( topology_uid ) FROM topology"
149 static struct StatementHandle *get_topology;
150
151 #define GET_DHTKEYUID_STMT "SELECT dhtkeyuid FROM dhtkeys where dhtkey = ? and trialuid = ?"
152 static struct StatementHandle *get_dhtkeyuid;
153
154 #define GET_NODEUID_STMT "SELECT nodeuid FROM nodes where trialuid = ? and nodeid = ?"
155 static struct StatementHandle *get_nodeuid;
156
157 #define INSERT_TOPOLOGY_STMT "INSERT INTO topology (trialuid, date, connections) "\
158                              "VALUES (?, NOW(), ?)"
159 static struct StatementHandle *insert_topology;
160
161 #define EXTEND_TOPOLOGY_STMT "INSERT INTO extended_topology (topology_uid, uid_first, uid_second) "\
162                              "VALUES (?, ?, ?)"
163 static struct StatementHandle *extend_topology;
164
165 #define SET_MALICIOUS_STMT "update nodes set malicious_dropper = 1  where trialuid = ? and nodeid = ?"
166 static struct StatementHandle *update_node_malicious;
167
168 #define UPDATE_TOPOLOGY_STMT "update topology set connections = ?  where topology_uid = ?"
169 static struct StatementHandle *update_topology;
170
171 /**
172  * Run a query (not a select statement)
173  *
174  * @return GNUNET_OK if executed, GNUNET_SYSERR if an error occurred
175  */
176 int
177 run_statement (const char *statement)
178 {
179   mysql_query (conn, statement);
180   if (mysql_error (conn)[0])
181     {
182       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
183                  "mysql_query");
184       return GNUNET_SYSERR;
185     }
186   return GNUNET_OK;
187 }
188
189 /*
190  * Creates tables if they don't already exist for dht logging
191  */
192 static int
193 itable ()
194 {
195 #define MRUNS(a) (GNUNET_OK != run_statement (a) )
196
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;
205
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;
214
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;
228
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;
244
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;
279
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;
287
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;
296
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;
320
321   if (MRUNS ("SET AUTOCOMMIT = 1"))
322     return GNUNET_SYSERR;
323
324   return GNUNET_OK;
325 #undef MRUNS
326 }
327
328 /**
329  * Create a prepared statement.
330  *
331  * @return NULL on error
332  */
333 struct StatementHandle *
334 prepared_statement_create (const char *statement)
335 {
336   struct StatementHandle *ret;
337
338   ret = GNUNET_malloc (sizeof (struct StatementHandle));
339   ret->query = GNUNET_strdup (statement);
340   return ret;
341 }
342
343 /**
344  * Close a prepared statement.
345  *
346  * @return NULL on error
347  */
348 void
349 prepared_statement_close (struct StatementHandle *s)
350 {
351   if (s == NULL)
352     {
353       return;
354     }
355
356   GNUNET_free_non_null(s->query);
357
358   if (s->valid == GNUNET_YES)
359     mysql_stmt_close(s->statement);
360   GNUNET_free(s);
361 }
362
363 /*
364  * Initialize the prepared statements for use with dht test logging
365  */
366 static int
367 iopen (struct GNUNET_DHTLOG_Plugin *plugin)
368 {
369   int ret;
370   my_bool reconnect;
371   unsigned int timeout;
372   char *user;
373   char *password;
374   char *server;
375   char *database;
376   unsigned long long port;
377
378   conn = mysql_init (NULL);
379   if (conn == NULL)
380     return GNUNET_SYSERR;
381
382   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (plugin->cfg,
383                                                          "MYSQL", "DATABASE",
384                                                          &database))
385     {
386       database = GNUNET_strdup("gnunet");
387     }
388
389   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (plugin->cfg,
390                                                           "MYSQL", "USER", &user))
391     {
392       user = GNUNET_strdup("dht");
393     }
394
395   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (plugin->cfg,
396                                                           "MYSQL", "PASSWORD", &password))
397     {
398       password = GNUNET_strdup("dhttest**");
399     }
400
401   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (plugin->cfg,
402                                                           "MYSQL", "SERVER", &server))
403     {
404       server = GNUNET_strdup("localhost");
405     }
406
407   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (plugin->cfg,
408                                                           "MYSQL", "MYSQL_PORT", &port))
409     {
410       port = 0;
411     }
412
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);
415
416   reconnect = 0;
417   timeout = 60; /* in seconds */
418   mysql_options (conn, MYSQL_OPT_RECONNECT, &reconnect);
419   mysql_options (conn,
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);
426
427   GNUNET_free_non_null(server);
428   GNUNET_free_non_null(password);
429   GNUNET_free_non_null(user);
430   GNUNET_free_non_null(database);
431
432   if (mysql_error (conn)[0])
433     {
434       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
435                  "mysql_real_connect");
436       return GNUNET_SYSERR;
437     }
438
439 #if OLD
440   db = GNUNET_MYSQL_database_open (coreAPI->ectx, coreAPI->cfg);
441   if (db == NULL)
442     return GNUNET_SYSERR;
443 #endif
444
445   ret = itable ();
446
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) )
465     {
466       return GNUNET_SYSERR;
467     }
468 #undef PINIT
469
470   return ret;
471 }
472
473 static int
474 return_ok (void *cls, unsigned int num_values, MYSQL_BIND * values)
475 {
476   return GNUNET_OK;
477 }
478
479 /**
480  * Prepare a statement for running.
481  *
482  * @return GNUNET_OK on success
483  */
484 static int
485 prepare_statement (struct StatementHandle *ret)
486 {
487   if (GNUNET_YES == ret->valid)
488     return GNUNET_OK;
489
490   ret->statement = mysql_stmt_init (conn);
491   if (ret->statement == NULL)
492     return GNUNET_SYSERR;
493
494   if (mysql_stmt_prepare (ret->statement, ret->query, strlen (ret->query)))
495     {
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;
501     }
502   ret->valid = GNUNET_YES;
503   return GNUNET_OK;
504 }
505
506 /**
507  * Bind the parameters for the given MySQL statement
508  * and run it.
509  *
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
513  */
514 static int
515 init_params (struct StatementHandle *s, va_list ap)
516 {
517   MYSQL_BIND qbind[MAX_PARAM];
518   unsigned int pc;
519   unsigned int off;
520   enum enum_field_types ft;
521
522   pc = mysql_stmt_param_count (s->statement);
523   if (pc > MAX_PARAM)
524     {
525       /* increase internal constant! */
526       GNUNET_break (0);
527       return GNUNET_SYSERR;
528     }
529   memset (qbind, 0, sizeof (qbind));
530   off = 0;
531   ft = 0;
532   while ((pc > 0) && (-1 != (ft = va_arg (ap, enum enum_field_types))))
533     {
534       qbind[off].buffer_type = ft;
535       switch (ft)
536         {
537         case MYSQL_TYPE_FLOAT:
538           qbind[off].buffer = va_arg (ap, float *);
539           break;
540         case MYSQL_TYPE_LONGLONG:
541           qbind[off].buffer = va_arg (ap, unsigned long long *);
542           qbind[off].is_unsigned = va_arg (ap, int);
543           break;
544         case MYSQL_TYPE_LONG:
545           qbind[off].buffer = va_arg (ap, unsigned int *);
546           qbind[off].is_unsigned = va_arg (ap, int);
547           break;
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 *);
554           break;
555         default:
556           /* unsupported type */
557           GNUNET_break (0);
558           return GNUNET_SYSERR;
559         }
560       pc--;
561       off++;
562     }
563   if (!((pc == 0) && (ft != -1) && (va_arg (ap, int) == -1)))
564     {
565       GNUNET_break (0);
566       return GNUNET_SYSERR;
567     }
568   if (mysql_stmt_bind_param (s->statement, qbind))
569     {
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;
575     }
576
577   if (mysql_stmt_execute (s->statement))
578     {
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;
584     }
585
586   return GNUNET_OK;
587 }
588
589 /**
590  * Run a prepared SELECT statement.
591  *
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
599  *        with "-1"
600  * @return GNUNET_SYSERR on error, otherwise
601  *         the number of successfully affected (or queried) rows
602  */
603 int
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,
609                                ...)
610 {
611   va_list ap;
612   int ret;
613   unsigned int rsize;
614   int total;
615
616   if (GNUNET_OK != prepare_statement (s))
617     {
618       GNUNET_break (0);
619       return GNUNET_SYSERR;
620     }
621   va_start (ap, processor_cls);
622   if (GNUNET_OK != init_params (s, ap))
623     {
624       GNUNET_break (0);
625       va_end (ap);
626       return GNUNET_SYSERR;
627     }
628   va_end (ap);
629   rsize = mysql_stmt_field_count (s->statement);
630   if (rsize > result_size)
631     {
632       GNUNET_break (0);
633       return GNUNET_SYSERR;
634     }
635   if (mysql_stmt_bind_result (s->statement, results))
636     {
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;
642     }
643
644   total = 0;
645   while (1)
646     {
647       ret = mysql_stmt_fetch (s->statement);
648       if (ret == MYSQL_NO_DATA)
649         break;
650       if (ret != 0)
651         {
652           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
653                        _("`%s' failed at %s:%d with error: %s\n"),
654                        "mysql_stmt_fetch",
655                        __FILE__, __LINE__, mysql_stmt_error (s->statement));
656           return GNUNET_SYSERR;
657         }
658       if (processor != NULL)
659         if (GNUNET_OK != processor (processor_cls, rsize, results))
660           break;
661       total++;
662     }
663   mysql_stmt_reset (s->statement);
664   return total;
665 }
666
667
668 static int
669 get_node_uid (unsigned long long *nodeuid, const GNUNET_HashCode * peerHash)
670 {
671   MYSQL_BIND rbind[1];
672   struct GNUNET_CRYPTO_HashAsciiEncoded encPeer;
673   unsigned long long p_len;
674
675   int ret;
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;
680
681   GNUNET_CRYPTO_hash_to_enc (peerHash, &encPeer);
682   p_len = strlen ((char *) &encPeer);
683
684   if (1 != (ret = prepared_statement_run_select (get_nodeuid,
685                                                               1,
686                                                               rbind,
687                                                               return_ok,
688                                                               NULL,
689                                                               MYSQL_TYPE_LONGLONG,
690                                                               &current_trial,
691                                                               GNUNET_YES,
692                                                               MYSQL_TYPE_VAR_STRING,
693                                                               &encPeer,
694                                                               max_varchar_len,
695                                                               &p_len, -1)))
696     {
697 #if DEBUG_DHTLOG
698       fprintf (stderr, "FAILED\n");
699 #endif
700       return GNUNET_SYSERR;
701     }
702   return GNUNET_OK;
703 }
704
705 static int
706 get_current_trial (unsigned long long *trialuid)
707 {
708   MYSQL_BIND rbind[1];
709
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;
714
715   if ((GNUNET_OK !=
716        prepared_statement_run_select (get_trial,
717                                       1,
718                                       rbind,
719                                       return_ok, NULL, -1)))
720     {
721       return GNUNET_SYSERR;
722     }
723
724   return GNUNET_OK;
725 }
726
727 static int
728 get_current_topology (unsigned long long *topologyuid)
729 {
730   MYSQL_BIND rbind[1];
731
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;
736
737   if ((GNUNET_OK !=
738        prepared_statement_run_select (get_topology,
739                                       1,
740                                       rbind,
741                                       return_ok, NULL, -1)))
742     {
743       return GNUNET_SYSERR;
744     }
745
746   return GNUNET_OK;
747 }
748
749 static int
750 get_dhtkey_uid (unsigned long long *dhtkeyuid, const GNUNET_HashCode * key)
751 {
752   MYSQL_BIND rbind[1];
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);
761 #if DEBUG_DHTLOG
762   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Searching for dhtkey `%s' in trial %llu\n", GNUNET_h2s(key), current_trial);
763 #endif
764   if ((GNUNET_OK !=
765        prepared_statement_run_select (get_dhtkeyuid,
766                                       1,
767                                       rbind,
768                                       return_ok, NULL,
769                                       MYSQL_TYPE_VAR_STRING,
770                                       &encKey,
771                                       max_varchar_len,
772                                       &k_len,
773                                       MYSQL_TYPE_LONGLONG,
774                                       &current_trial,
775                                       GNUNET_YES, -1)))
776     {
777       return GNUNET_SYSERR;
778     }
779
780   return GNUNET_OK;
781 }
782
783 /**
784  * Run a prepared statement that does NOT produce results.
785  *
786  * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective
787  *        values (size + buffer-reference for pointers); terminated
788  *        with "-1"
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
793  */
794 int
795 prepared_statement_run (struct StatementHandle *s,
796                         unsigned long long *insert_id, ...)
797 {
798   va_list ap;
799   int affected;
800
801   if (GNUNET_OK != prepare_statement(s))
802     {
803       GNUNET_break(0);
804       return GNUNET_SYSERR;
805     }
806   GNUNET_assert(s->valid == GNUNET_YES);
807   if (s->statement == NULL)
808     return GNUNET_SYSERR;
809
810   va_start (ap, insert_id);
811
812   if (GNUNET_OK != init_params (s, ap))
813     {
814       va_end (ap);
815       return GNUNET_SYSERR;
816     }
817
818   va_end (ap);
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);
823
824   return affected;
825 }
826
827 /*
828  * Inserts the specified trial into the dhttests.trials table
829  *
830  * @param trialuid return the trialuid of the newly inserted trial
831  * @param other_identifier identifier for the trial from another source
832  *        (for joining later)
833  * @param num_nodes how many nodes are in the trial
834  * @param topology integer representing topology for this trial
835  * @param blacklist_topology integer representing blacklist topology for this trial
836  * @param connect_topology integer representing connect topology for this trial
837  * @param connect_topology_option integer representing connect topology option
838  * @param connect_topology_option_modifier float to modify connect option
839  * @param topology_percentage percentage modifier for certain topologies
840  * @param topology_probability probability modifier for certain topologies
841  * @param puts number of puts to perform
842  * @param gets number of gets to perform
843  * @param concurrent number of concurrent requests
844  * @param settle_time time to wait between creating topology and starting testing
845  * @param num_rounds number of times to repeat the trial
846  * @param malicious_getters number of malicious GET peers in the trial
847  * @param malicious_putters number of malicious PUT peers in the trial
848  * @param malicious_droppers number of malicious DROP peers in the trial
849  * @param malicious_get_frequency how often malicious gets are sent
850  * @param malicious_put_frequency how often malicious puts are sent
851  * @param stop_closest stop forwarding PUTs if closest node found
852  * @param stop_found stop forwarding GETs if data found
853  * @param strict_kademlia test used kademlia routing algorithm
854  * @param gets_succeeded how many gets did the test driver report success on
855  * @param message string to put into DB for this trial
856  *
857  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
858  */
859 int add_trial (unsigned long long *trialuid, unsigned int other_identifier, unsigned int num_nodes, unsigned int topology,
860                unsigned int blacklist_topology, unsigned int connect_topology,
861                unsigned int connect_topology_option, float connect_topology_option_modifier,
862                float topology_percentage, float topology_probability,
863                unsigned int puts, unsigned int gets, unsigned int concurrent, unsigned int settle_time,
864                unsigned int num_rounds, unsigned int malicious_getters, unsigned int malicious_putters,
865                unsigned int malicious_droppers, unsigned int malicious_get_frequency,
866                unsigned int malicious_put_frequency, unsigned int stop_closest, unsigned int stop_found,
867                unsigned int strict_kademlia, unsigned int gets_succeeded,
868                char *message)
869 {
870   MYSQL_STMT *stmt;
871   int ret;
872   unsigned long long m_len;
873   m_len = strlen (message);
874
875   stmt = mysql_stmt_init(conn);
876   if (GNUNET_OK !=
877       (ret = prepared_statement_run (insert_trial, trialuid,
878                                      MYSQL_TYPE_LONG, &other_identifier, GNUNET_YES,
879                                      MYSQL_TYPE_LONG, &num_nodes, GNUNET_YES,
880                                      MYSQL_TYPE_LONG, &topology, GNUNET_YES,
881                                      MYSQL_TYPE_FLOAT, &topology_percentage,
882                                      MYSQL_TYPE_FLOAT, &topology_probability,
883                                      MYSQL_TYPE_LONG, &blacklist_topology, GNUNET_YES,
884                                      MYSQL_TYPE_LONG, &connect_topology, GNUNET_YES,
885                                      MYSQL_TYPE_LONG, &connect_topology_option, GNUNET_YES,
886                                      MYSQL_TYPE_FLOAT, &connect_topology_option_modifier,
887                                      MYSQL_TYPE_LONG, &puts, GNUNET_YES,
888                                      MYSQL_TYPE_LONG, &gets, GNUNET_YES,
889                                      MYSQL_TYPE_LONG, &concurrent, GNUNET_YES,
890                                      MYSQL_TYPE_LONG, &settle_time, GNUNET_YES,
891                                      MYSQL_TYPE_LONG, &num_rounds, GNUNET_YES,
892                                      MYSQL_TYPE_LONG, &malicious_getters, GNUNET_YES,
893                                      MYSQL_TYPE_LONG, &malicious_putters, GNUNET_YES,
894                                      MYSQL_TYPE_LONG, &malicious_droppers, GNUNET_YES,
895                                      MYSQL_TYPE_LONG, &malicious_get_frequency, GNUNET_YES,
896                                      MYSQL_TYPE_LONG, &malicious_put_frequency, GNUNET_YES,
897                                      MYSQL_TYPE_LONG, &stop_closest, GNUNET_YES,
898                                      MYSQL_TYPE_LONG, &stop_found, GNUNET_YES,
899                                      MYSQL_TYPE_LONG, &strict_kademlia, GNUNET_YES,
900                                      MYSQL_TYPE_LONG, &gets_succeeded, GNUNET_YES,
901                                      MYSQL_TYPE_BLOB, message, max_varchar_len +
902                                      max_varchar_len, &m_len,
903                                       -1)))
904     {
905       if (ret == GNUNET_SYSERR)
906         {
907           mysql_stmt_close(stmt);
908           return GNUNET_SYSERR;
909         }
910     }
911
912   get_current_trial (&current_trial);
913
914   mysql_stmt_close(stmt);
915   return GNUNET_OK;
916 }
917
918
919 /*
920  * Inserts the specified stats into the dhttests.node_statistics table
921  *
922  * @param peer the peer inserting the statistic
923  * @param route_requests route requests seen
924  * @param route_forwards route requests forwarded
925  * @param result_requests route result requests seen
926  * @param client_requests client requests initiated
927  * @param result_forwards route results forwarded
928  * @param gets get requests handled
929  * @param puts put requests handle
930  * @param data_inserts data inserted at this node
931  * @param find_peer_requests find peer requests seen
932  * @param find_peers_started find peer requests initiated at this node
933  * @param gets_started get requests initiated at this node
934  * @param puts_started put requests initiated at this node
935  * @param find_peer_responses_received find peer responses received locally
936  * @param get_responses_received get responses received locally
937  * @param find_peer_responses_sent find peer responses sent from this node
938  * @param get_responses_sent get responses sent from this node
939  *
940  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
941  */
942 int
943 add_stat (const struct GNUNET_PeerIdentity *peer, unsigned int route_requests,
944           unsigned int route_forwards, unsigned int result_requests,
945           unsigned int client_requests, unsigned int result_forwards,
946           unsigned int gets, unsigned int puts,
947           unsigned int data_inserts, unsigned int find_peer_requests,
948           unsigned int find_peers_started, unsigned int gets_started,
949           unsigned int puts_started, unsigned int find_peer_responses_received,
950           unsigned int get_responses_received, unsigned int find_peer_responses_sent,
951           unsigned int get_responses_sent)
952 {
953   MYSQL_STMT *stmt;
954   int ret;
955   unsigned long long peer_uid;
956   unsigned long long return_uid;
957   if (peer == NULL)
958     return GNUNET_SYSERR;
959
960   if (GNUNET_OK != get_node_uid (&peer_uid, &peer->hashPubKey))
961     {
962       return GNUNET_SYSERR;
963     }
964
965   stmt = mysql_stmt_init(conn);
966   if (GNUNET_OK !=
967       (ret = prepared_statement_run (insert_stat,
968                                      &return_uid,
969                                      MYSQL_TYPE_LONGLONG, &current_trial, GNUNET_YES,
970                                      MYSQL_TYPE_LONGLONG, &peer_uid, GNUNET_YES,
971                                      MYSQL_TYPE_LONG, &route_requests, GNUNET_YES,
972                                      MYSQL_TYPE_LONG, &route_forwards, GNUNET_YES,
973                                      MYSQL_TYPE_LONG, &result_requests, GNUNET_YES,
974                                      MYSQL_TYPE_LONG, &client_requests, GNUNET_YES,
975                                      MYSQL_TYPE_LONG, &result_forwards, GNUNET_YES,
976                                      MYSQL_TYPE_LONG, &gets, GNUNET_YES,
977                                      MYSQL_TYPE_LONG, &puts, GNUNET_YES,
978                                      MYSQL_TYPE_LONG, &data_inserts, GNUNET_YES,
979                                      MYSQL_TYPE_LONG, &find_peer_requests, GNUNET_YES,
980                                      MYSQL_TYPE_LONG, &find_peers_started, GNUNET_YES,
981                                      MYSQL_TYPE_LONG, &gets_started, GNUNET_YES,
982                                      MYSQL_TYPE_LONG, &puts_started, GNUNET_YES,
983                                      MYSQL_TYPE_LONG, &find_peer_responses_received, GNUNET_YES,
984                                      MYSQL_TYPE_LONG, &get_responses_received, GNUNET_YES,
985                                      MYSQL_TYPE_LONG, &find_peer_responses_sent, GNUNET_YES,
986                                      MYSQL_TYPE_LONG, &get_responses_sent, GNUNET_YES,
987                                      -1)))
988     {
989       if (ret == GNUNET_SYSERR)
990         {
991           mysql_stmt_close(stmt);
992           return GNUNET_SYSERR;
993         }
994     }
995
996   mysql_stmt_close(stmt);
997   return GNUNET_OK;
998 }
999
1000 /*
1001  * Inserts the specified stats into the dhttests.generic_stats table
1002  *
1003  * @param peer the peer inserting the statistic
1004  * @param name the name of the statistic
1005  * @param section the section of the statistic
1006  * @param value the value of the statistic
1007  *
1008  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1009  */
1010 int
1011 add_generic_stat (const struct GNUNET_PeerIdentity *peer,
1012                   const char *name,
1013                   const char *section, uint64_t value)
1014 {
1015   unsigned long long peer_uid;
1016   unsigned long long section_len;
1017   unsigned long long name_len;
1018   int ret;
1019   if (peer == NULL)
1020     return GNUNET_SYSERR;
1021
1022   if (GNUNET_OK != get_node_uid (&peer_uid, &peer->hashPubKey))
1023     {
1024       return GNUNET_SYSERR;
1025     }
1026
1027   section_len = strlen(section);
1028   name_len = strlen(name);
1029
1030   if (GNUNET_OK !=
1031       (ret = prepared_statement_run (insert_generic_stat,
1032                                      NULL,
1033                                      MYSQL_TYPE_LONGLONG, &current_trial, GNUNET_YES,
1034                                      MYSQL_TYPE_LONGLONG, &peer_uid, GNUNET_YES,
1035                                      MYSQL_TYPE_VAR_STRING, &section, max_varchar_len, &section_len,
1036                                      MYSQL_TYPE_VAR_STRING, &name, max_varchar_len, &name_len,
1037                                      MYSQL_TYPE_LONGLONG, &value, GNUNET_YES,
1038                                      -1)))
1039     {
1040       if (ret == GNUNET_SYSERR)
1041         {
1042           return GNUNET_SYSERR;
1043         }
1044     }
1045   return GNUNET_OK;
1046 }
1047
1048 /*
1049  * Inserts the specified dhtkey into the dhttests.dhtkeys table,
1050  * stores return value of dhttests.dhtkeys.dhtkeyuid into dhtkeyuid
1051  *
1052  * @param dhtkeyuid return value
1053  * @param dhtkey hashcode of key to insert
1054  *
1055  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1056  */
1057 int
1058 add_dhtkey (unsigned long long *dhtkeyuid, const GNUNET_HashCode * dhtkey)
1059 {
1060
1061   int ret;
1062   struct GNUNET_CRYPTO_HashAsciiEncoded encKey;
1063   unsigned long long k_len;
1064   unsigned long long h_len;
1065   unsigned long long curr_dhtkeyuid;
1066   GNUNET_CRYPTO_hash_to_enc (dhtkey, &encKey);
1067   k_len = strlen ((char *) &encKey);
1068   h_len = sizeof (GNUNET_HashCode);
1069   curr_dhtkeyuid = 0;
1070   ret = get_dhtkey_uid(&curr_dhtkeyuid, dhtkey);
1071   if (curr_dhtkeyuid != 0) /* dhtkey already exists */
1072     {
1073       if (dhtkeyuid != NULL)
1074         *dhtkeyuid = curr_dhtkeyuid;
1075       return GNUNET_OK;
1076     }
1077   else if (ret == GNUNET_SYSERR)
1078     {
1079 #if DEBUG_DHTLOG
1080       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Failed to get dhtkeyuid!\n");
1081 #endif
1082     }
1083
1084   if (GNUNET_OK !=
1085       (ret = prepared_statement_run (insert_dhtkey,
1086                                      dhtkeyuid,
1087                                      MYSQL_TYPE_VAR_STRING,
1088                                      &encKey,
1089                                      max_varchar_len,
1090                                      &k_len,
1091                                      MYSQL_TYPE_LONG,
1092                                      &current_trial,
1093                                      GNUNET_YES,
1094                                      MYSQL_TYPE_BLOB,
1095                                      dhtkey,
1096                                      sizeof (GNUNET_HashCode),
1097                                      &h_len, -1)))
1098     {
1099       if (ret == GNUNET_SYSERR)
1100         {
1101           return GNUNET_SYSERR;
1102         }
1103     }
1104
1105   return GNUNET_OK;
1106 }
1107
1108
1109
1110 /*
1111  * Inserts the specified node into the dhttests.nodes table
1112  *
1113  * @param nodeuid the inserted node uid
1114  * @param node the node to insert
1115  *
1116  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1117  */
1118 int
1119 add_node (unsigned long long *nodeuid, struct GNUNET_PeerIdentity * node)
1120 {
1121   struct GNUNET_CRYPTO_HashAsciiEncoded encPeer;
1122   unsigned long p_len;
1123   unsigned long h_len;
1124   int ret;
1125
1126   if (node == NULL)
1127     return GNUNET_SYSERR;
1128
1129   GNUNET_CRYPTO_hash_to_enc (&node->hashPubKey, &encPeer);
1130   p_len = (unsigned long) strlen ((char *) &encPeer);
1131   h_len = sizeof (GNUNET_HashCode);
1132   if (GNUNET_OK !=
1133       (ret = prepared_statement_run (insert_node,
1134                                      nodeuid,
1135                                      MYSQL_TYPE_LONGLONG, &current_trial, GNUNET_YES,
1136                                      MYSQL_TYPE_VAR_STRING, &encPeer, max_varchar_len, &p_len,
1137                                      MYSQL_TYPE_BLOB, &node->hashPubKey, sizeof (GNUNET_HashCode),
1138                                      &h_len, -1)))
1139     {
1140       if (ret == GNUNET_SYSERR)
1141         {
1142           return GNUNET_SYSERR;
1143         }
1144     }
1145   return GNUNET_OK;
1146 }
1147
1148 /*
1149  * Update dhttests.trials table with current server time as end time
1150  *
1151  * @param trialuid trial to update
1152  * @param gets_succeeded how many gets did the testcase report as successful
1153  *
1154  * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1155  */
1156 int
1157 update_trials (unsigned long long trialuid,
1158                unsigned int gets_succeeded)
1159 {
1160   int ret;
1161
1162   if (GNUNET_OK !=
1163       (ret = prepared_statement_run (update_trial,
1164                                     NULL,
1165                                     MYSQL_TYPE_LONG, &gets_succeeded, GNUNET_YES,
1166                                     MYSQL_TYPE_LONGLONG, &trialuid, GNUNET_YES,
1167                                     -1)))
1168     {
1169       if (ret == GNUNET_SYSERR)
1170         {
1171           return GNUNET_SYSERR;
1172         }
1173     }
1174   if (ret > 0)
1175     return GNUNET_OK;
1176   else
1177     return GNUNET_SYSERR;
1178 }
1179
1180
1181 /*
1182  * Update dhttests.nodes table setting the identified
1183  * node as a malicious dropper.
1184  *
1185  * @param peer the peer that was set to be malicious
1186  *
1187  * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1188  */
1189 int set_malicious (struct GNUNET_PeerIdentity *peer)
1190 {
1191   unsigned long long p_len;
1192   int ret;
1193   char *temp_str;
1194
1195   temp_str = GNUNET_strdup(GNUNET_h2s_full(&peer->hashPubKey));
1196   p_len = strlen(temp_str);
1197
1198   if (GNUNET_OK !=
1199       (ret = prepared_statement_run (update_node_malicious,
1200                                     NULL,
1201                                     MYSQL_TYPE_LONGLONG, &current_trial, GNUNET_YES,
1202                                     MYSQL_TYPE_VAR_STRING, temp_str, max_varchar_len, &p_len,
1203                                     -1)))
1204     {
1205       if (ret == GNUNET_SYSERR)
1206         {
1207           return GNUNET_SYSERR;
1208         }
1209     }
1210   return GNUNET_OK;
1211 }
1212
1213
1214 /*
1215  * Update dhttests.trials table with total connections information
1216  *
1217  * @param trialuid the trialuid to update
1218  * @param totalConnections the number of connections
1219  *
1220  * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1221  */
1222 int
1223 add_connections (unsigned long long trialuid, unsigned int totalConnections)
1224 {
1225   int ret;
1226
1227   if (GNUNET_OK !=
1228       (ret = prepared_statement_run (update_connection,
1229                                                   NULL,
1230                                                   MYSQL_TYPE_LONG,
1231                                                   &totalConnections,
1232                                                   GNUNET_YES,
1233                                                   MYSQL_TYPE_LONGLONG,
1234                                                   &trialuid, GNUNET_YES, -1)))
1235     {
1236       if (ret == GNUNET_SYSERR)
1237         {
1238           return GNUNET_SYSERR;
1239         }
1240     }
1241   if (ret > 0)
1242     return GNUNET_OK;
1243   else
1244     return GNUNET_SYSERR;
1245 }
1246
1247 /*
1248  * Inserts the specified query into the dhttests.queries table
1249  *
1250  * @param sqlqueruid inserted query uid
1251  * @param queryid dht query id
1252  * @param type type of the query
1253  * @param hops number of hops query traveled
1254  * @param succeeded whether or not query was successful
1255  * @param node the node the query hit
1256  * @param key the key of the query
1257  *
1258  * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1259  */
1260 int
1261 add_query (unsigned long long *sqlqueryuid, unsigned long long queryid,
1262            unsigned int type, unsigned int hops, int succeeded,
1263            const struct GNUNET_PeerIdentity * node, const GNUNET_HashCode * key)
1264 {
1265   int ret;
1266   unsigned long long peer_uid, key_uid;
1267   peer_uid = 0;
1268   key_uid = 0;
1269
1270   if ((node != NULL)
1271       && (GNUNET_OK == get_node_uid (&peer_uid, &node->hashPubKey)))
1272     {
1273
1274     }
1275   else
1276     {
1277       return GNUNET_SYSERR;
1278     }
1279
1280   if ((key != NULL) && (GNUNET_OK == get_dhtkey_uid (&key_uid, key)))
1281     {
1282
1283     }
1284   else if ((key != NULL) && (key->bits[(512 / 8 / sizeof (unsigned int)) - 1] == 42))   /* Malicious marker */
1285     {
1286       key_uid = 0;
1287     }
1288   else
1289     {
1290       return GNUNET_SYSERR;
1291     }
1292
1293   if (GNUNET_OK !=
1294       (ret = prepared_statement_run (insert_query,
1295                                                   sqlqueryuid,
1296                                                   MYSQL_TYPE_LONGLONG,
1297                                                   &current_trial,
1298                                                   GNUNET_YES,
1299                                                   MYSQL_TYPE_LONG,
1300                                                   &type,
1301                                                   GNUNET_NO,
1302                                                   MYSQL_TYPE_LONG,
1303                                                   &hops,
1304                                                   GNUNET_YES,
1305                                                   MYSQL_TYPE_LONGLONG,
1306                                                   &key_uid,
1307                                                   GNUNET_YES,
1308                                                   MYSQL_TYPE_LONGLONG,
1309                                                   &queryid,
1310                                                   GNUNET_YES,
1311                                                   MYSQL_TYPE_LONG,
1312                                                   &succeeded,
1313                                                   GNUNET_NO,
1314                                                   MYSQL_TYPE_LONGLONG,
1315                                                   &peer_uid, GNUNET_YES, -1)))
1316     {
1317       if (ret == GNUNET_SYSERR)
1318         {
1319           return GNUNET_SYSERR;
1320         }
1321     }
1322   if (ret > 0)
1323     return GNUNET_OK;
1324   else
1325     return GNUNET_SYSERR;
1326 }
1327
1328 /*
1329  * Inserts the specified route information into the dhttests.routes table
1330  *
1331  * @param sqlqueruid inserted query uid
1332  * @param queryid dht query id
1333  * @param type type of the query
1334  * @param hops number of hops query traveled
1335  * @param succeeded whether or not query was successful
1336  * @param node the node the query hit
1337  * @param key the key of the query
1338  * @param from_node the node that sent the message to node
1339  * @param to_node next node to forward message to
1340  *
1341  * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1342  */
1343 int
1344 add_route (unsigned long long *sqlqueryuid, unsigned long long queryid,
1345            unsigned int type, unsigned int hops,
1346            int succeeded, const struct GNUNET_PeerIdentity * node,
1347            const GNUNET_HashCode * key, const struct GNUNET_PeerIdentity * from_node,
1348            const struct GNUNET_PeerIdentity * to_node)
1349 {
1350   unsigned long long peer_uid = 0;
1351   unsigned long long key_uid = 0;
1352   unsigned long long from_uid = 0;
1353   unsigned long long to_uid = 0;
1354   int ret;
1355
1356   if (from_node != NULL)
1357     get_node_uid (&from_uid, &from_node->hashPubKey);
1358   else
1359     from_uid = 0;
1360
1361   if (to_node != NULL)
1362     get_node_uid (&to_uid, &to_node->hashPubKey);
1363   else
1364     to_uid = 0;
1365
1366   if ((node != NULL))
1367     {
1368       if (1 != get_node_uid (&peer_uid, &node->hashPubKey))
1369         {
1370           return GNUNET_SYSERR;
1371         }
1372     }
1373   else
1374     return GNUNET_SYSERR;
1375
1376   if ((key != NULL))
1377     {
1378       if (1 != get_dhtkey_uid (&key_uid, key))
1379         {
1380           return GNUNET_SYSERR;
1381         }
1382     }
1383   else
1384     return GNUNET_SYSERR;
1385
1386   if (GNUNET_OK !=
1387       (ret = prepared_statement_run (insert_route,
1388                                     sqlqueryuid,
1389                                     MYSQL_TYPE_LONGLONG,
1390                                     &current_trial,
1391                                     GNUNET_YES,
1392                                     MYSQL_TYPE_LONG,
1393                                     &type,
1394                                     GNUNET_NO,
1395                                     MYSQL_TYPE_LONG,
1396                                     &hops,
1397                                     GNUNET_YES,
1398                                     MYSQL_TYPE_LONGLONG,
1399                                     &key_uid,
1400                                     GNUNET_YES,
1401                                     MYSQL_TYPE_LONGLONG,
1402                                     &queryid,
1403                                     GNUNET_YES,
1404                                     MYSQL_TYPE_LONG,
1405                                     &succeeded,
1406                                     GNUNET_NO,
1407                                     MYSQL_TYPE_LONGLONG,
1408                                     &peer_uid,
1409                                     GNUNET_YES,
1410                                     MYSQL_TYPE_LONGLONG,
1411                                     &from_uid,
1412                                     GNUNET_YES,
1413                                     MYSQL_TYPE_LONGLONG,
1414                                     &to_uid, GNUNET_YES, -1)))
1415     {
1416       if (ret == GNUNET_SYSERR)
1417         {
1418           return GNUNET_SYSERR;
1419         }
1420     }
1421   if (ret > 0)
1422     return GNUNET_OK;
1423   else
1424     return GNUNET_SYSERR;
1425 }
1426
1427 /*
1428  * Update dhttests.topology table with total connections information
1429  *
1430  * @param totalConnections the number of connections
1431  *
1432  * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1433  */
1434 int
1435 update_current_topology (unsigned int connections)
1436 {
1437   int ret;
1438   unsigned long long topologyuid;
1439
1440   get_current_topology(&topologyuid);
1441
1442   if (GNUNET_OK !=
1443       (ret = prepared_statement_run (update_topology,
1444                                      NULL,
1445                                      MYSQL_TYPE_LONG,
1446                                      &connections,
1447                                      GNUNET_YES,
1448                                      MYSQL_TYPE_LONGLONG,
1449                                      &topologyuid, GNUNET_YES, -1)))
1450     {
1451       if (ret == GNUNET_SYSERR)
1452         {
1453           return GNUNET_SYSERR;
1454         }
1455     }
1456   if (ret > 0)
1457     return GNUNET_OK;
1458   else
1459     return GNUNET_SYSERR;
1460   return GNUNET_OK;
1461 }
1462
1463 /*
1464  * Records the current topology (number of connections, time, trial)
1465  *
1466  * @param num_connections how many connections are in the topology
1467  *
1468  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1469  */
1470 int
1471 add_topology (int num_connections)
1472 {
1473   int ret;
1474
1475   if (GNUNET_OK !=
1476       (ret = prepared_statement_run (insert_topology,
1477                                      NULL,
1478                                      MYSQL_TYPE_LONGLONG,
1479                                      &current_trial,
1480                                      GNUNET_YES,
1481                                      MYSQL_TYPE_LONG,
1482                                      &num_connections,
1483                                      GNUNET_YES, -1)))
1484     {
1485       if (ret == GNUNET_SYSERR)
1486         {
1487           return GNUNET_SYSERR;
1488         }
1489     }
1490   if (ret > 0)
1491     return GNUNET_OK;
1492   else
1493     return GNUNET_SYSERR;
1494   return GNUNET_OK;
1495 }
1496
1497 /*
1498  * Records a connection between two peers in the current topology
1499  *
1500  * @param first one side of the connection
1501  * @param second other side of the connection
1502  *
1503  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1504  */
1505 int
1506 add_extended_topology (const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second)
1507 {
1508   int ret;
1509   unsigned long long first_uid;
1510   unsigned long long second_uid;
1511   unsigned long long topologyuid;
1512
1513   if (GNUNET_OK != get_current_topology(&topologyuid))
1514     return GNUNET_SYSERR;
1515   if (GNUNET_OK != get_node_uid(&first_uid, &first->hashPubKey))
1516     return GNUNET_SYSERR;
1517   if (GNUNET_OK != get_node_uid(&second_uid, &second->hashPubKey))
1518     return GNUNET_SYSERR;
1519
1520   if (GNUNET_OK !=
1521       (ret = prepared_statement_run (extend_topology,
1522                                      NULL,
1523                                      MYSQL_TYPE_LONGLONG,
1524                                      &topologyuid,
1525                                      GNUNET_YES,
1526                                      MYSQL_TYPE_LONGLONG,
1527                                      &first_uid,
1528                                      GNUNET_YES,
1529                                      MYSQL_TYPE_LONGLONG,
1530                                      &second_uid,
1531                                      GNUNET_YES,-1)))
1532     {
1533       if (ret == GNUNET_SYSERR)
1534         {
1535           return GNUNET_SYSERR;
1536         }
1537     }
1538   if (ret > 0)
1539     return GNUNET_OK;
1540   else
1541     return GNUNET_SYSERR;
1542   return GNUNET_OK;
1543 }
1544
1545
1546 /*
1547  * Provides the dhtlog api
1548  *
1549  * @param c the configuration to use to connect to a server
1550  *
1551  * @return the handle to the server, or NULL on error
1552  */
1553 void *
1554 libgnunet_plugin_dhtlog_mysql_init (void * cls)
1555 {
1556   struct GNUNET_DHTLOG_Plugin *plugin = cls;
1557
1558   cfg = plugin->cfg;
1559   max_varchar_len = 255;
1560 #if DEBUG_DHTLOG
1561   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MySQL DHT Logger: initializing database\n");
1562 #endif
1563
1564   if (iopen (plugin) != GNUNET_OK)
1565     {
1566       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1567                   _("Failed to initialize MySQL database connection for dhtlog.\n"));
1568       return NULL;
1569     }
1570
1571   GNUNET_assert(plugin->dhtlog_api == NULL);
1572   plugin->dhtlog_api = GNUNET_malloc(sizeof(struct GNUNET_DHTLOG_Handle));
1573   plugin->dhtlog_api->insert_trial = &add_trial;
1574   plugin->dhtlog_api->insert_stat = &add_stat;
1575   plugin->dhtlog_api->add_generic_stat = &add_generic_stat;
1576   plugin->dhtlog_api->insert_query = &add_query;
1577   plugin->dhtlog_api->update_trial = &update_trials;
1578   plugin->dhtlog_api->insert_route = &add_route;
1579   plugin->dhtlog_api->insert_node = &add_node;
1580   plugin->dhtlog_api->insert_dhtkey = &add_dhtkey;
1581   plugin->dhtlog_api->update_connections = &add_connections;
1582   plugin->dhtlog_api->insert_topology = &add_topology;
1583   plugin->dhtlog_api->update_topology = &update_current_topology;
1584   plugin->dhtlog_api->insert_extended_topology = &add_extended_topology;
1585   plugin->dhtlog_api->set_malicious = &set_malicious;
1586   plugin->dhtlog_api->add_generic_stat = &add_generic_stat;
1587   get_current_trial (&current_trial);
1588
1589   return plugin;
1590 }
1591
1592 /**
1593  * Shutdown the plugin.
1594  */
1595 void *
1596 libgnunet_plugin_dhtlog_mysql_done (void * cls)
1597 {
1598   struct GNUNET_DHTLOG_Handle *dhtlog_api = cls;
1599
1600   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1601               "MySQL DHT Logger: database shutdown\n");
1602   GNUNET_assert(dhtlog_api != NULL);
1603   prepared_statement_close(insert_query);
1604   prepared_statement_close(insert_route);
1605   prepared_statement_close(insert_trial);
1606   prepared_statement_close(insert_node);
1607   prepared_statement_close(insert_dhtkey);
1608   prepared_statement_close(update_trial);
1609   prepared_statement_close(get_dhtkeyuid);
1610   prepared_statement_close(get_nodeuid);
1611   prepared_statement_close(update_connection);
1612   prepared_statement_close(get_trial);
1613   prepared_statement_close(get_topology);
1614   prepared_statement_close(insert_topology);
1615   prepared_statement_close(update_topology);
1616   prepared_statement_close(extend_topology);
1617   prepared_statement_close(update_node_malicious);
1618
1619   if (conn != NULL)
1620     mysql_close (conn);
1621   conn = NULL;
1622   mysql_library_end();
1623   GNUNET_free(dhtlog_api);
1624   return NULL;
1625 }
1626
1627 /* end of plugin_dhtlog_mysql.c */