nitpicks
[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_NO
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, 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              "`numnodes` int(10) unsigned NOT NULL,"
248              "`topology` int(10) NOT NULL,"
249              "`starttime` datetime NOT NULL,"
250              "`endtime` datetime NOT NULL,"
251              "`puts` int(10) unsigned NOT NULL,"
252              "`gets` int(10) unsigned NOT NULL,"
253              "`concurrent` int(10) unsigned NOT NULL,"
254              "`settle_time` int(10) unsigned NOT NULL,"
255              "`totalConnections` int(10) unsigned NOT NULL,"
256              "`message` text NOT NULL,"
257              "`num_rounds` int(10) unsigned NOT NULL,"
258              "`malicious_getters` int(10) unsigned NOT NULL,"
259              "`malicious_putters` int(10) unsigned NOT NULL,"
260              "`malicious_droppers` int(10) unsigned NOT NULL,"
261              "`totalMessagesDropped` int(10) unsigned NOT NULL,"
262              "`totalBytesDropped` int(10) unsigned NOT NULL,"
263              "`topology_modifier` double NOT NULL,"
264              "`logNMultiplier` double NOT NULL,"
265              "`maxnetbps` bigint(20) unsigned NOT NULL,"
266              "`unknownPeers` int(10) unsigned NOT NULL,"
267              "PRIMARY KEY  (`trialuid`),"
268              "UNIQUE KEY `trialuid` (`trialuid`)"
269              ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1"))
270     return GNUNET_SYSERR;
271
272   if (MRUNS ("CREATE TABLE IF NOT EXISTS `topology` ("
273               "`topology_uid` int(10) unsigned NOT NULL AUTO_INCREMENT,"
274               "`trialuid` int(10) unsigned NOT NULL,"
275               "`date` datetime NOT NULL,"
276               "`connections` int(10) unsigned NOT NULL,"
277               "PRIMARY KEY (`topology_uid`)) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1"))
278     return GNUNET_SYSERR;
279
280   if (MRUNS ("CREATE TABLE IF NOT EXISTS `extended_topology` ("
281              "`extended_uid` int(10) unsigned NOT NULL AUTO_INCREMENT,"
282              "`topology_uid` int(10) unsigned NOT NULL,"
283              "`uid_first` int(10) unsigned NOT NULL,"
284              "`uid_second` int(10) unsigned NOT NULL,"
285              "PRIMARY KEY (`extended_uid`)"
286              ") ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1"))
287     return GNUNET_SYSERR;
288
289   if (MRUNS ("CREATE TABLE IF NOT EXISTS `node_statistics` ("
290               "`stat_uid` int(10) unsigned NOT NULL AUTO_INCREMENT,"
291               "`trialuid` int(10) unsigned NOT NULL,"
292               "`nodeuid` int(10) unsigned NOT NULL,"
293               "`route_requests` int(10) unsigned NOT NULL,"
294               "`route_forwards` int(10) unsigned NOT NULL,"
295               "`result_requests` int(10) unsigned NOT NULL,"
296               "`client_results` int(10) unsigned NOT NULL,"
297               "`result_forwards` int(10) unsigned NOT NULL,"
298               "`gets` int(10) unsigned NOT NULL,"
299               "`puts` int(10) unsigned NOT NULL,"
300               "`data_inserts` int(10) unsigned NOT NULL,"
301               "`find_peer_requests` int(10) unsigned NOT NULL,"
302               "`find_peers_started` int(10) unsigned NOT NULL,"
303               "`gets_started` int(10) unsigned NOT NULL,"
304               "`puts_started` int(10) unsigned NOT NULL,"
305               "`find_peer_responses_received` int(10) unsigned NOT NULL,"
306               "`get_responses_received` int(10) unsigned NOT NULL,"
307               "`find_peer_responses_sent` int(10) unsigned NOT NULL,"
308               "`get_responses_sent` int(10) unsigned NOT NULL,"
309              "PRIMARY KEY (`stat_uid`)"
310             ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;"))
311     return GNUNET_SYSERR;
312
313   if (MRUNS ("SET AUTOCOMMIT = 1"))
314     return GNUNET_SYSERR;
315
316   return GNUNET_OK;
317 #undef MRUNS
318 }
319
320 /**
321  * Create a prepared statement.
322  *
323  * @return NULL on error
324  */
325 struct StatementHandle *
326 prepared_statement_create (const char *statement)
327 {
328   struct StatementHandle *ret;
329
330   ret = GNUNET_malloc (sizeof (struct StatementHandle));
331   ret->query = GNUNET_strdup (statement);
332   return ret;
333 }
334
335 /**
336  * Close a prepared statement.
337  *
338  * @return NULL on error
339  */
340 void
341 prepared_statement_close (struct StatementHandle *s)
342 {
343   if (s == NULL)
344     {
345       return;
346     }
347
348   GNUNET_free_non_null(s->query);
349
350   if (s->valid == GNUNET_YES)
351     mysql_stmt_close(s->statement);
352   GNUNET_free(s);
353 }
354
355 /*
356  * Initialize the prepared statements for use with dht test logging
357  */
358 static int
359 iopen (struct GNUNET_DHTLOG_Plugin *plugin)
360 {
361   int ret;
362   my_bool reconnect;
363   unsigned int timeout;
364   char *user;
365   char *password;
366   char *server;
367   char *database;
368   unsigned long long port;
369
370   conn = mysql_init (NULL);
371   if (conn == NULL)
372     return GNUNET_SYSERR;
373
374   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (plugin->cfg,
375                                                          "MYSQL", "DATABASE",
376                                                          &database))
377     {
378       database = GNUNET_strdup("gnunet");
379     }
380
381   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (plugin->cfg,
382                                                           "MYSQL", "USER", &user))
383     {
384       user = GNUNET_strdup("dht");
385     }
386
387   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (plugin->cfg,
388                                                           "MYSQL", "PASSWORD", &password))
389     {
390       password = GNUNET_strdup("dhttest**");
391     }
392
393   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (plugin->cfg,
394                                                           "MYSQL", "SERVER", &server))
395     {
396       server = GNUNET_strdup("localhost");
397     }
398
399   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (plugin->cfg,
400                                                           "MYSQL", "MYSQL_PORT", &port))
401     {
402       port = 0;
403     }
404
405   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to mysql with: user %s, pass %s, server %s, database %s, port %d\n",
406               user, password, server, database, port);
407
408   reconnect = 0;
409   timeout = 60; /* in seconds */
410   mysql_options (conn, MYSQL_OPT_RECONNECT, &reconnect);
411   mysql_options (conn,
412                  MYSQL_OPT_CONNECT_TIMEOUT, (const void *) &timeout);
413   mysql_options(conn, MYSQL_SET_CHARSET_NAME, "UTF8");
414   mysql_options (conn, MYSQL_OPT_READ_TIMEOUT, (const void *) &timeout);
415   mysql_options (conn, MYSQL_OPT_WRITE_TIMEOUT, (const void *) &timeout);
416   mysql_real_connect (conn, server, user, password,
417                       database, (unsigned int) port, NULL, CLIENT_IGNORE_SIGPIPE);
418
419   GNUNET_free_non_null(server);
420   GNUNET_free_non_null(password);
421   GNUNET_free_non_null(user);
422   GNUNET_free_non_null(database);
423
424   if (mysql_error (conn)[0])
425     {
426       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
427                  "mysql_real_connect");
428       return GNUNET_SYSERR;
429     }
430
431 #if OLD
432   db = GNUNET_MYSQL_database_open (coreAPI->ectx, coreAPI->cfg);
433   if (db == NULL)
434     return GNUNET_SYSERR;
435 #endif
436
437   ret = itable ();
438
439 #define PINIT(a,b) (NULL == (a = prepared_statement_create(b)))
440   if (PINIT (insert_query, INSERT_QUERIES_STMT) ||
441       PINIT (insert_route, INSERT_ROUTES_STMT) ||
442       PINIT (insert_trial, INSERT_TRIALS_STMT) ||
443       PINIT (insert_stat, INSERT_STAT_STMT) ||
444       PINIT (insert_generic_stat, INSERT_GENERIC_STAT_STMT) ||
445       PINIT (insert_node, INSERT_NODES_STMT) ||
446       PINIT (insert_dhtkey, INSERT_DHTKEY_STMT) ||
447       PINIT (update_trial, UPDATE_TRIALS_STMT) ||
448       PINIT (get_dhtkeyuid, GET_DHTKEYUID_STMT) ||
449       PINIT (get_nodeuid, GET_NODEUID_STMT) ||
450       PINIT (update_connection, UPDATE_CONNECTIONS_STMT) ||
451       PINIT (get_trial, GET_TRIAL_STMT) ||
452       PINIT (get_topology, GET_TOPOLOGY_STMT) ||
453       PINIT (insert_topology, INSERT_TOPOLOGY_STMT) ||
454       PINIT (update_topology, UPDATE_TOPOLOGY_STMT) ||
455       PINIT (extend_topology, EXTEND_TOPOLOGY_STMT) ||
456       PINIT (update_node_malicious, SET_MALICIOUS_STMT) )
457     {
458       return GNUNET_SYSERR;
459     }
460 #undef PINIT
461
462   return ret;
463 }
464
465 static int
466 return_ok (void *cls, unsigned int num_values, MYSQL_BIND * values)
467 {
468   return GNUNET_OK;
469 }
470
471 /**
472  * Prepare a statement for running.
473  *
474  * @return GNUNET_OK on success
475  */
476 static int
477 prepare_statement (struct StatementHandle *ret)
478 {
479   if (GNUNET_YES == ret->valid)
480     return GNUNET_OK;
481
482   ret->statement = mysql_stmt_init (conn);
483   if (ret->statement == NULL)
484     return GNUNET_SYSERR;
485
486   if (mysql_stmt_prepare (ret->statement, ret->query, strlen (ret->query)))
487     {
488       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
489                  "mysql_stmt_prepare `%s', %s", ret->query, mysql_error(conn));
490       mysql_stmt_close (ret->statement);
491       ret->statement = NULL;
492       return GNUNET_SYSERR;
493     }
494   ret->valid = GNUNET_YES;
495   return GNUNET_OK;
496 }
497
498 /**
499  * Bind the parameters for the given MySQL statement
500  * and run it.
501  *
502  * @param s statement to bind and run
503  * @param ap arguments for the binding
504  * @return GNUNET_SYSERR on error, GNUNET_OK on success
505  */
506 static int
507 init_params (struct StatementHandle *s, va_list ap)
508 {
509   MYSQL_BIND qbind[MAX_PARAM];
510   unsigned int pc;
511   unsigned int off;
512   enum enum_field_types ft;
513
514   pc = mysql_stmt_param_count (s->statement);
515   if (pc > MAX_PARAM)
516     {
517       /* increase internal constant! */
518       GNUNET_break (0);
519       return GNUNET_SYSERR;
520     }
521   memset (qbind, 0, sizeof (qbind));
522   off = 0;
523   ft = 0;
524   while ((pc > 0) && (-1 != (ft = va_arg (ap, enum enum_field_types))))
525     {
526       qbind[off].buffer_type = ft;
527       switch (ft)
528         {
529         case MYSQL_TYPE_FLOAT:
530           qbind[off].buffer = va_arg (ap, float *);
531           break;
532         case MYSQL_TYPE_LONGLONG:
533           qbind[off].buffer = va_arg (ap, unsigned long long *);
534           qbind[off].is_unsigned = va_arg (ap, int);
535           break;
536         case MYSQL_TYPE_LONG:
537           qbind[off].buffer = va_arg (ap, unsigned int *);
538           qbind[off].is_unsigned = va_arg (ap, int);
539           break;
540         case MYSQL_TYPE_VAR_STRING:
541         case MYSQL_TYPE_STRING:
542         case MYSQL_TYPE_BLOB:
543           qbind[off].buffer = va_arg (ap, void *);
544           qbind[off].buffer_length = va_arg (ap, unsigned long);
545           qbind[off].length = va_arg (ap, unsigned long *);
546           break;
547         default:
548           /* unsupported type */
549           GNUNET_break (0);
550           return GNUNET_SYSERR;
551         }
552       pc--;
553       off++;
554     }
555   if (!((pc == 0) && (ft != -1) && (va_arg (ap, int) == -1)))
556     {
557       GNUNET_break (0);
558       return GNUNET_SYSERR;
559     }
560   if (mysql_stmt_bind_param (s->statement, qbind))
561     {
562       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
563                   _("`%s' failed at %s:%d with error: %s\n"),
564                   "mysql_stmt_bind_param",
565                    __FILE__, __LINE__, mysql_stmt_error (s->statement));
566       return GNUNET_SYSERR;
567     }
568
569   if (mysql_stmt_execute (s->statement))
570     {
571     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
572                _("`%s' failed at %s:%d with error: %s\n"),
573                "mysql_stmt_execute",
574                __FILE__, __LINE__, mysql_stmt_error (s->statement));
575       return GNUNET_SYSERR;
576     }
577
578   return GNUNET_OK;
579 }
580
581 /**
582  * Run a prepared SELECT statement.
583  *
584  * @param result_size number of elements in results array
585  * @param results pointer to already initialized MYSQL_BIND
586  *        array (of sufficient size) for passing results
587  * @param processor function to call on each result
588  * @param processor_cls extra argument to processor
589  * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective
590  *        values (size + buffer-reference for pointers); terminated
591  *        with "-1"
592  * @return GNUNET_SYSERR on error, otherwise
593  *         the number of successfully affected (or queried) rows
594  */
595 int
596 prepared_statement_run_select (struct StatementHandle
597                                *s, unsigned int result_size,
598                                MYSQL_BIND * results,
599                                GNUNET_MysqlDataProcessor
600                                processor, void *processor_cls,
601                                ...)
602 {
603   va_list ap;
604   int ret;
605   unsigned int rsize;
606   int total;
607
608   if (GNUNET_OK != prepare_statement (s))
609     {
610       GNUNET_break (0);
611       return GNUNET_SYSERR;
612     }
613   va_start (ap, processor_cls);
614   if (GNUNET_OK != init_params (s, ap))
615     {
616       GNUNET_break (0);
617       va_end (ap);
618       return GNUNET_SYSERR;
619     }
620   va_end (ap);
621   rsize = mysql_stmt_field_count (s->statement);
622   if (rsize > result_size)
623     {
624       GNUNET_break (0);
625       return GNUNET_SYSERR;
626     }
627   if (mysql_stmt_bind_result (s->statement, results))
628     {
629       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
630                   _("`%s' failed at %s:%d with error: %s\n"),
631                   "mysql_stmt_bind_result",
632                   __FILE__, __LINE__, mysql_stmt_error (s->statement));
633       return GNUNET_SYSERR;
634     }
635
636   total = 0;
637   while (1)
638     {
639       ret = mysql_stmt_fetch (s->statement);
640       if (ret == MYSQL_NO_DATA)
641         break;
642       if (ret != 0)
643         {
644           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
645                        _("`%s' failed at %s:%d with error: %s\n"),
646                        "mysql_stmt_fetch",
647                        __FILE__, __LINE__, mysql_stmt_error (s->statement));
648           return GNUNET_SYSERR;
649         }
650       if (processor != NULL)
651         if (GNUNET_OK != processor (processor_cls, rsize, results))
652           break;
653       total++;
654     }
655   mysql_stmt_reset (s->statement);
656   return total;
657 }
658
659
660 static int
661 get_node_uid (unsigned long long *nodeuid, const GNUNET_HashCode * peerHash)
662 {
663   MYSQL_BIND rbind[1];
664   struct GNUNET_CRYPTO_HashAsciiEncoded encPeer;
665   unsigned long long p_len;
666
667   int ret;
668   memset (rbind, 0, sizeof (rbind));
669   rbind[0].buffer_type = MYSQL_TYPE_LONGLONG;
670   rbind[0].buffer = nodeuid;
671   rbind[0].is_unsigned = GNUNET_YES;
672
673   GNUNET_CRYPTO_hash_to_enc (peerHash, &encPeer);
674   p_len = strlen ((char *) &encPeer);
675
676   if (1 != (ret = prepared_statement_run_select (get_nodeuid,
677                                                               1,
678                                                               rbind,
679                                                               return_ok,
680                                                               NULL,
681                                                               MYSQL_TYPE_LONGLONG,
682                                                               &current_trial,
683                                                               GNUNET_YES,
684                                                               MYSQL_TYPE_VAR_STRING,
685                                                               &encPeer,
686                                                               max_varchar_len,
687                                                               &p_len, -1)))
688     {
689 #if DEBUG_DHTLOG
690       fprintf (stderr, "FAILED\n");
691 #endif
692       return GNUNET_SYSERR;
693     }
694   return GNUNET_OK;
695 }
696
697 static int
698 get_current_trial (unsigned long long *trialuid)
699 {
700   MYSQL_BIND rbind[1];
701
702   memset (rbind, 0, sizeof (rbind));
703   rbind[0].buffer_type = MYSQL_TYPE_LONG;
704   rbind[0].is_unsigned = 1;
705   rbind[0].buffer = trialuid;
706
707   if ((GNUNET_OK !=
708        prepared_statement_run_select (get_trial,
709                                       1,
710                                       rbind,
711                                       return_ok, NULL, -1)))
712     {
713       return GNUNET_SYSERR;
714     }
715
716   return GNUNET_OK;
717 }
718
719 static int
720 get_current_topology (unsigned long long *topologyuid)
721 {
722   MYSQL_BIND rbind[1];
723
724   memset (rbind, 0, sizeof (rbind));
725   rbind[0].buffer_type = MYSQL_TYPE_LONGLONG;
726   rbind[0].is_unsigned = 1;
727   rbind[0].buffer = topologyuid;
728
729   if ((GNUNET_OK !=
730        prepared_statement_run_select (get_topology,
731                                       1,
732                                       rbind,
733                                       return_ok, NULL, -1)))
734     {
735       return GNUNET_SYSERR;
736     }
737
738   return GNUNET_OK;
739 }
740
741 static int
742 get_dhtkey_uid (unsigned long long *dhtkeyuid, const GNUNET_HashCode * key)
743 {
744   MYSQL_BIND rbind[1];
745   struct GNUNET_CRYPTO_HashAsciiEncoded encKey;
746   unsigned long long k_len;
747   memset (rbind, 0, sizeof (rbind));
748   rbind[0].buffer_type = MYSQL_TYPE_LONG;
749   rbind[0].is_unsigned = 1;
750   rbind[0].buffer = dhtkeyuid;
751   GNUNET_CRYPTO_hash_to_enc (key, &encKey);
752   k_len = strlen ((char *) &encKey);
753
754   if ((GNUNET_OK !=
755        prepared_statement_run_select (get_dhtkeyuid,
756                                       1,
757                                       rbind,
758                                       return_ok, NULL,
759                                       MYSQL_TYPE_VAR_STRING,
760                                       &encKey,
761                                       max_varchar_len,
762                                       &k_len,
763                                       MYSQL_TYPE_LONGLONG,
764                                       &current_trial,
765                                       GNUNET_YES, -1)))
766     {
767       return GNUNET_SYSERR;
768     }
769
770   return GNUNET_OK;
771 }
772
773 /**
774  * Run a prepared statement that does NOT produce results.
775  *
776  * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective
777  *        values (size + buffer-reference for pointers); terminated
778  *        with "-1"
779  * @param insert_id NULL or address where to store the row ID of whatever
780  *        was inserted (only for INSERT statements!)
781  * @return GNUNET_SYSERR on error, otherwise
782  *         the number of successfully affected rows
783  */
784 int
785 prepared_statement_run (struct StatementHandle *s,
786                         unsigned long long *insert_id, ...)
787 {
788   va_list ap;
789   int affected;
790
791   if (GNUNET_OK != prepare_statement(s))
792     {
793       GNUNET_break(0);
794       return GNUNET_SYSERR;
795     }
796   GNUNET_assert(s->valid == GNUNET_YES);
797   if (s->statement == NULL)
798     return GNUNET_SYSERR;
799
800   va_start (ap, insert_id);
801
802   if (GNUNET_OK != init_params (s, ap))
803     {
804       va_end (ap);
805       return GNUNET_SYSERR;
806     }
807
808   va_end (ap);
809   affected = mysql_stmt_affected_rows (s->statement);
810   if (NULL != insert_id)
811     *insert_id = (unsigned long long) mysql_stmt_insert_id (s->statement);
812   mysql_stmt_reset (s->statement);
813
814   return affected;
815 }
816
817 /*
818  * Inserts the specified trial into the dhttests.trials table
819  *
820  * @param trialuid return the trialuid of the newly inserted trial
821  * @param num_nodes how many nodes are in the trial
822  * @param topology integer representing topology for this trial
823  * @param blacklist_topology integer representing blacklist topology for this trial
824  * @param connect_topology integer representing connect topology for this trial
825  * @param connect_topology_option integer representing connect topology option
826  * @param connect_topology_option_modifier float to modify connect option
827  * @param topology_percentage percentage modifier for certain topologies
828  * @param topology_probability probability modifier for certain topologies
829  * @param puts number of puts to perform
830  * @param gets number of gets to perform
831  * @param concurrent number of concurrent requests
832  * @param settle_time time to wait between creating topology and starting testing
833  * @param num_rounds number of times to repeat the trial
834  * @param malicious_getters number of malicious GET peers in the trial
835  * @param malicious_putters number of malicious PUT peers in the trial
836  * @param malicious_droppers number of malicious DROP peers in the trial
837  * @param malicious_get_frequency how often malicious gets are sent
838  * @param malicious_put_frequency how often malicious puts are sent
839  * @param stop_closest stop forwarding PUTs if closest node found
840  * @param stop_found stop forwarding GETs if data found
841  * @param strict_kademlia test used kademlia routing algorithm
842  * @param gets_succeeded how many gets did the test driver report success on
843  * @param message string to put into DB for this trial
844  *
845  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
846  */
847 int add_trial (unsigned long long *trialuid, unsigned int num_nodes, unsigned int topology,
848                unsigned int blacklist_topology, unsigned int connect_topology,
849                unsigned int connect_topology_option, float connect_topology_option_modifier,
850                float topology_percentage, float topology_probability,
851                unsigned int puts, unsigned int gets, unsigned int concurrent, unsigned int settle_time,
852                unsigned int num_rounds, unsigned int malicious_getters, unsigned int malicious_putters,
853                unsigned int malicious_droppers, unsigned int malicious_get_frequency,
854                unsigned int malicious_put_frequency, unsigned int stop_closest, unsigned int stop_found,
855                unsigned int strict_kademlia, unsigned int gets_succeeded,
856                char *message)
857 {
858   MYSQL_STMT *stmt;
859   int ret;
860   unsigned long long m_len;
861   m_len = strlen (message);
862
863   stmt = mysql_stmt_init(conn);
864   if (GNUNET_OK !=
865       (ret = prepared_statement_run (insert_trial, trialuid,
866                                      MYSQL_TYPE_LONG, &num_nodes, GNUNET_YES,
867                                      MYSQL_TYPE_LONG, &topology, GNUNET_YES,
868                                      MYSQL_TYPE_FLOAT, &topology_percentage,
869                                      MYSQL_TYPE_FLOAT, &topology_probability,
870                                      MYSQL_TYPE_LONG, &blacklist_topology, GNUNET_YES,
871                                      MYSQL_TYPE_LONG, &connect_topology, GNUNET_YES,
872                                      MYSQL_TYPE_LONG, &connect_topology_option, GNUNET_YES,
873                                      MYSQL_TYPE_FLOAT, &connect_topology_option_modifier,
874                                      MYSQL_TYPE_LONG, &puts, GNUNET_YES,
875                                      MYSQL_TYPE_LONG, &gets, GNUNET_YES,
876                                      MYSQL_TYPE_LONG, &concurrent, GNUNET_YES,
877                                      MYSQL_TYPE_LONG, &settle_time, GNUNET_YES,
878                                      MYSQL_TYPE_LONG, &num_rounds, GNUNET_YES,
879                                      MYSQL_TYPE_LONG, &malicious_getters, GNUNET_YES,
880                                      MYSQL_TYPE_LONG, &malicious_putters, GNUNET_YES,
881                                      MYSQL_TYPE_LONG, &malicious_droppers, GNUNET_YES,
882                                      MYSQL_TYPE_LONG, &malicious_get_frequency, GNUNET_YES,
883                                      MYSQL_TYPE_LONG, &malicious_put_frequency, GNUNET_YES,
884                                      MYSQL_TYPE_LONG, &stop_closest, GNUNET_YES,
885                                      MYSQL_TYPE_LONG, &stop_found, GNUNET_YES,
886                                      MYSQL_TYPE_LONG, &strict_kademlia, GNUNET_YES,
887                                      MYSQL_TYPE_LONG, &gets_succeeded, GNUNET_YES,
888                                      MYSQL_TYPE_BLOB, message, max_varchar_len +
889                                      max_varchar_len, &m_len,
890                                       -1)))
891     {
892       if (ret == GNUNET_SYSERR)
893         {
894           mysql_stmt_close(stmt);
895           return GNUNET_SYSERR;
896         }
897     }
898
899   get_current_trial (&current_trial);
900
901   mysql_stmt_close(stmt);
902   return GNUNET_OK;
903 }
904
905
906 /*
907  * Inserts the specified stats into the dhttests.node_statistics table
908  *
909  * @param peer the peer inserting the statistic
910  * @param route_requests route requests seen
911  * @param route_forwards route requests forwarded
912  * @param result_requests route result requests seen
913  * @param client_requests client requests initiated
914  * @param result_forwards route results forwarded
915  * @param gets get requests handled
916  * @param puts put requests handle
917  * @param data_inserts data inserted at this node
918  * @param find_peer_requests find peer requests seen
919  * @param find_peers_started find peer requests initiated at this node
920  * @param gets_started get requests initiated at this node
921  * @param puts_started put requests initiated at this node
922  * @param find_peer_responses_received find peer responses received locally
923  * @param get_responses_received get responses received locally
924  * @param find_peer_responses_sent find peer responses sent from this node
925  * @param get_responses_sent get responses sent from this node
926  *
927  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
928  */
929 int
930 add_stat (const struct GNUNET_PeerIdentity *peer, unsigned int route_requests,
931           unsigned int route_forwards, unsigned int result_requests,
932           unsigned int client_requests, unsigned int result_forwards,
933           unsigned int gets, unsigned int puts,
934           unsigned int data_inserts, unsigned int find_peer_requests,
935           unsigned int find_peers_started, unsigned int gets_started,
936           unsigned int puts_started, unsigned int find_peer_responses_received,
937           unsigned int get_responses_received, unsigned int find_peer_responses_sent,
938           unsigned int get_responses_sent)
939 {
940   MYSQL_STMT *stmt;
941   int ret;
942   unsigned long long peer_uid;
943   unsigned long long return_uid;
944   if (peer == NULL)
945     return GNUNET_SYSERR;
946
947   if (GNUNET_OK != get_node_uid (&peer_uid, &peer->hashPubKey))
948     {
949       return GNUNET_SYSERR;
950     }
951
952   stmt = mysql_stmt_init(conn);
953   if (GNUNET_OK !=
954       (ret = prepared_statement_run (insert_stat,
955                                      &return_uid,
956                                      MYSQL_TYPE_LONGLONG, &current_trial, GNUNET_YES,
957                                      MYSQL_TYPE_LONGLONG, &peer_uid, GNUNET_YES,
958                                      MYSQL_TYPE_LONG, &route_requests, GNUNET_YES,
959                                      MYSQL_TYPE_LONG, &route_forwards, GNUNET_YES,
960                                      MYSQL_TYPE_LONG, &result_requests, GNUNET_YES,
961                                      MYSQL_TYPE_LONG, &client_requests, GNUNET_YES,
962                                      MYSQL_TYPE_LONG, &result_forwards, GNUNET_YES,
963                                      MYSQL_TYPE_LONG, &gets, GNUNET_YES,
964                                      MYSQL_TYPE_LONG, &puts, GNUNET_YES,
965                                      MYSQL_TYPE_LONG, &data_inserts, GNUNET_YES,
966                                      MYSQL_TYPE_LONG, &find_peer_requests, GNUNET_YES,
967                                      MYSQL_TYPE_LONG, &find_peers_started, GNUNET_YES,
968                                      MYSQL_TYPE_LONG, &gets_started, GNUNET_YES,
969                                      MYSQL_TYPE_LONG, &puts_started, GNUNET_YES,
970                                      MYSQL_TYPE_LONG, &find_peer_responses_received, GNUNET_YES,
971                                      MYSQL_TYPE_LONG, &get_responses_received, GNUNET_YES,
972                                      MYSQL_TYPE_LONG, &find_peer_responses_sent, GNUNET_YES,
973                                      MYSQL_TYPE_LONG, &get_responses_sent, GNUNET_YES,
974                                      -1)))
975     {
976       if (ret == GNUNET_SYSERR)
977         {
978           mysql_stmt_close(stmt);
979           return GNUNET_SYSERR;
980         }
981     }
982
983   mysql_stmt_close(stmt);
984   return GNUNET_OK;
985 }
986
987 /*
988  * Inserts the specified stats into the dhttests.generic_stats table
989  *
990  * @param peer the peer inserting the statistic
991  * @param name the name of the statistic
992  * @param section the section of the statistic
993  * @param value the value of the statistic
994  *
995  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
996  */
997 int
998 add_generic_stat (const struct GNUNET_PeerIdentity *peer,
999                   const char *name,
1000                   const char *section, uint64_t value)
1001 {
1002   unsigned long long peer_uid;
1003   unsigned long long section_len;
1004   unsigned long long name_len;
1005   int ret;
1006   if (peer == NULL)
1007     return GNUNET_SYSERR;
1008
1009   if (GNUNET_OK != get_node_uid (&peer_uid, &peer->hashPubKey))
1010     {
1011       return GNUNET_SYSERR;
1012     }
1013
1014   section_len = strlen(section);
1015   name_len = strlen(name);
1016
1017   if (GNUNET_OK !=
1018       (ret = prepared_statement_run (insert_generic_stat,
1019                                      NULL,
1020                                      MYSQL_TYPE_LONGLONG, &current_trial, GNUNET_YES,
1021                                      MYSQL_TYPE_LONGLONG, &peer_uid, GNUNET_YES,
1022                                      MYSQL_TYPE_VAR_STRING, &section, max_varchar_len, &section_len,
1023                                      MYSQL_TYPE_VAR_STRING, &name, max_varchar_len, &name_len,
1024                                      MYSQL_TYPE_LONGLONG, &value, GNUNET_YES,
1025                                      -1)))
1026     {
1027       if (ret == GNUNET_SYSERR)
1028         {
1029           return GNUNET_SYSERR;
1030         }
1031     }
1032   return GNUNET_OK;
1033 }
1034
1035 /*
1036  * Inserts the specified dhtkey into the dhttests.dhtkeys table,
1037  * stores return value of dhttests.dhtkeys.dhtkeyuid into dhtkeyuid
1038  *
1039  * @param dhtkeyuid return value
1040  * @param dhtkey hashcode of key to insert
1041  *
1042  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1043  */
1044 int
1045 add_dhtkey (unsigned long long *dhtkeyuid, const GNUNET_HashCode * dhtkey)
1046 {
1047
1048   int ret;
1049   struct GNUNET_CRYPTO_HashAsciiEncoded encKey;
1050   unsigned long long k_len;
1051   unsigned long long h_len;
1052   unsigned long long curr_dhtkeyuid;
1053   GNUNET_CRYPTO_hash_to_enc (dhtkey, &encKey);
1054   k_len = strlen ((char *) &encKey);
1055   h_len = sizeof (GNUNET_HashCode);
1056   curr_dhtkeyuid = 0;
1057   ret = get_dhtkey_uid(&curr_dhtkeyuid, dhtkey);
1058   if (curr_dhtkeyuid != 0) /* dhtkey already exists */
1059     {
1060       if (dhtkeyuid != NULL)
1061         *dhtkeyuid = curr_dhtkeyuid;
1062       return GNUNET_OK;
1063     }
1064   else if (ret == GNUNET_SYSERR)
1065     return GNUNET_SYSERR;
1066
1067   if (GNUNET_OK !=
1068       (ret = prepared_statement_run (insert_dhtkey,
1069                                      dhtkeyuid,
1070                                      MYSQL_TYPE_VAR_STRING,
1071                                      &encKey,
1072                                      max_varchar_len,
1073                                      &k_len,
1074                                      MYSQL_TYPE_LONG,
1075                                      &current_trial,
1076                                      GNUNET_YES,
1077                                      MYSQL_TYPE_BLOB,
1078                                      dhtkey,
1079                                      sizeof (GNUNET_HashCode),
1080                                      &h_len, -1)))
1081     {
1082       if (ret == GNUNET_SYSERR)
1083         {
1084           return GNUNET_SYSERR;
1085         }
1086     }
1087
1088   return GNUNET_OK;
1089 }
1090
1091
1092
1093 /*
1094  * Inserts the specified node into the dhttests.nodes table
1095  *
1096  * @param nodeuid the inserted node uid
1097  * @param node the node to insert
1098  *
1099  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1100  */
1101 int
1102 add_node (unsigned long long *nodeuid, struct GNUNET_PeerIdentity * node)
1103 {
1104   struct GNUNET_CRYPTO_HashAsciiEncoded encPeer;
1105   unsigned long p_len;
1106   unsigned long h_len;
1107   int ret;
1108
1109   if (node == NULL)
1110     return GNUNET_SYSERR;
1111
1112   GNUNET_CRYPTO_hash_to_enc (&node->hashPubKey, &encPeer);
1113   p_len = (unsigned long) strlen ((char *) &encPeer);
1114   h_len = sizeof (GNUNET_HashCode);
1115   if (GNUNET_OK !=
1116       (ret = prepared_statement_run (insert_node,
1117                                      nodeuid,
1118                                      MYSQL_TYPE_LONGLONG, &current_trial, GNUNET_YES,
1119                                      MYSQL_TYPE_VAR_STRING, &encPeer, max_varchar_len, &p_len,
1120                                      MYSQL_TYPE_BLOB, &node->hashPubKey, sizeof (GNUNET_HashCode),
1121                                      &h_len, -1)))
1122     {
1123       if (ret == GNUNET_SYSERR)
1124         {
1125           return GNUNET_SYSERR;
1126         }
1127     }
1128   return GNUNET_OK;
1129 }
1130
1131 /*
1132  * Update dhttests.trials table with current server time as end time
1133  *
1134  * @param trialuid trial to update
1135  * @param gets_succeeded how many gets did the testcase report as successful
1136  *
1137  * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1138  */
1139 int
1140 update_trials (unsigned long long trialuid,
1141                unsigned int gets_succeeded)
1142 {
1143   int ret;
1144
1145   if (GNUNET_OK !=
1146       (ret = prepared_statement_run (update_trial,
1147                                     NULL,
1148                                     MYSQL_TYPE_LONG, &gets_succeeded, GNUNET_YES,
1149                                     MYSQL_TYPE_LONGLONG, &trialuid, GNUNET_YES,
1150                                     -1)))
1151     {
1152       if (ret == GNUNET_SYSERR)
1153         {
1154           return GNUNET_SYSERR;
1155         }
1156     }
1157   if (ret > 0)
1158     return GNUNET_OK;
1159   else
1160     return GNUNET_SYSERR;
1161 }
1162
1163
1164 /*
1165  * Update dhttests.nodes table setting the identified
1166  * node as a malicious dropper.
1167  *
1168  * @param peer the peer that was set to be malicious
1169  *
1170  * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1171  */
1172 int set_malicious (struct GNUNET_PeerIdentity *peer)
1173 {
1174   unsigned long long p_len;
1175   int ret;
1176   char *temp_str;
1177
1178   temp_str = GNUNET_strdup(GNUNET_h2s_full(&peer->hashPubKey));
1179   p_len = strlen(temp_str);
1180
1181   if (GNUNET_OK !=
1182       (ret = prepared_statement_run (update_node_malicious,
1183                                     NULL,
1184                                     MYSQL_TYPE_LONGLONG, &current_trial, GNUNET_YES,
1185                                     MYSQL_TYPE_VAR_STRING, temp_str, max_varchar_len, &p_len,
1186                                     -1)))
1187     {
1188       if (ret == GNUNET_SYSERR)
1189         {
1190           return GNUNET_SYSERR;
1191         }
1192     }
1193   return GNUNET_OK;
1194 }
1195
1196
1197 /*
1198  * Update dhttests.trials table with total connections information
1199  *
1200  * @param trialuid the trialuid to update
1201  * @param totalConnections the number of connections
1202  *
1203  * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1204  */
1205 int
1206 add_connections (unsigned long long trialuid, unsigned int totalConnections)
1207 {
1208   int ret;
1209
1210   if (GNUNET_OK !=
1211       (ret = prepared_statement_run (update_connection,
1212                                                   NULL,
1213                                                   MYSQL_TYPE_LONG,
1214                                                   &totalConnections,
1215                                                   GNUNET_YES,
1216                                                   MYSQL_TYPE_LONGLONG,
1217                                                   &trialuid, GNUNET_YES, -1)))
1218     {
1219       if (ret == GNUNET_SYSERR)
1220         {
1221           return GNUNET_SYSERR;
1222         }
1223     }
1224   if (ret > 0)
1225     return GNUNET_OK;
1226   else
1227     return GNUNET_SYSERR;
1228 }
1229
1230 /*
1231  * Inserts the specified query into the dhttests.queries table
1232  *
1233  * @param sqlqueruid inserted query uid
1234  * @param queryid dht query id
1235  * @param type type of the query
1236  * @param hops number of hops query traveled
1237  * @param succeeded whether or not query was successful
1238  * @param node the node the query hit
1239  * @param key the key of the query
1240  *
1241  * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1242  */
1243 int
1244 add_query (unsigned long long *sqlqueryuid, unsigned long long queryid,
1245            unsigned int type, unsigned int hops, int succeeded,
1246            const struct GNUNET_PeerIdentity * node, const GNUNET_HashCode * key)
1247 {
1248   int ret;
1249   unsigned long long peer_uid, key_uid;
1250   peer_uid = 0;
1251   key_uid = 0;
1252
1253   if ((node != NULL)
1254       && (GNUNET_OK == get_node_uid (&peer_uid, &node->hashPubKey)))
1255     {
1256
1257     }
1258   else
1259     {
1260       return GNUNET_SYSERR;
1261     }
1262
1263   if ((key != NULL) && (GNUNET_OK == get_dhtkey_uid (&key_uid, key)))
1264     {
1265
1266     }
1267   else if ((key != NULL) && (key->bits[(512 / 8 / sizeof (unsigned int)) - 1] == 42))   /* Malicious marker */
1268     {
1269       key_uid = 0;
1270     }
1271   else
1272     {
1273       return GNUNET_SYSERR;
1274     }
1275
1276   if (GNUNET_OK !=
1277       (ret = prepared_statement_run (insert_query,
1278                                                   sqlqueryuid,
1279                                                   MYSQL_TYPE_LONGLONG,
1280                                                   &current_trial,
1281                                                   GNUNET_YES,
1282                                                   MYSQL_TYPE_LONG,
1283                                                   &type,
1284                                                   GNUNET_NO,
1285                                                   MYSQL_TYPE_LONG,
1286                                                   &hops,
1287                                                   GNUNET_YES,
1288                                                   MYSQL_TYPE_LONGLONG,
1289                                                   &key_uid,
1290                                                   GNUNET_YES,
1291                                                   MYSQL_TYPE_LONGLONG,
1292                                                   &queryid,
1293                                                   GNUNET_YES,
1294                                                   MYSQL_TYPE_LONG,
1295                                                   &succeeded,
1296                                                   GNUNET_NO,
1297                                                   MYSQL_TYPE_LONGLONG,
1298                                                   &peer_uid, GNUNET_YES, -1)))
1299     {
1300       if (ret == GNUNET_SYSERR)
1301         {
1302           return GNUNET_SYSERR;
1303         }
1304     }
1305   if (ret > 0)
1306     return GNUNET_OK;
1307   else
1308     return GNUNET_SYSERR;
1309 }
1310
1311 /*
1312  * Inserts the specified route information into the dhttests.routes table
1313  *
1314  * @param sqlqueruid inserted query uid
1315  * @param queryid dht query id
1316  * @param type type of the query
1317  * @param hops number of hops query traveled
1318  * @param succeeded whether or not query was successful
1319  * @param node the node the query hit
1320  * @param key the key of the query
1321  * @param from_node the node that sent the message to node
1322  * @param to_node next node to forward message to
1323  *
1324  * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1325  */
1326 int
1327 add_route (unsigned long long *sqlqueryuid, unsigned long long queryid,
1328            unsigned int type, unsigned int hops,
1329            int succeeded, const struct GNUNET_PeerIdentity * node,
1330            const GNUNET_HashCode * key, const struct GNUNET_PeerIdentity * from_node,
1331            const struct GNUNET_PeerIdentity * to_node)
1332 {
1333   unsigned long long peer_uid = 0;
1334   unsigned long long key_uid = 0;
1335   unsigned long long from_uid = 0;
1336   unsigned long long to_uid = 0;
1337   int ret;
1338
1339   if (from_node != NULL)
1340     get_node_uid (&from_uid, &from_node->hashPubKey);
1341   else
1342     from_uid = 0;
1343
1344   if (to_node != NULL)
1345     get_node_uid (&to_uid, &to_node->hashPubKey);
1346   else
1347     to_uid = 0;
1348
1349   if ((node != NULL))
1350     {
1351       if (1 != get_node_uid (&peer_uid, &node->hashPubKey))
1352         {
1353           return GNUNET_SYSERR;
1354         }
1355     }
1356   else
1357     return GNUNET_SYSERR;
1358
1359   if ((key != NULL))
1360     {
1361       if (1 != get_dhtkey_uid (&key_uid, key))
1362         {
1363           return GNUNET_SYSERR;
1364         }
1365     }
1366   else
1367     return GNUNET_SYSERR;
1368
1369   if (GNUNET_OK !=
1370       (ret = prepared_statement_run (insert_route,
1371                                     sqlqueryuid,
1372                                     MYSQL_TYPE_LONGLONG,
1373                                     &current_trial,
1374                                     GNUNET_YES,
1375                                     MYSQL_TYPE_LONG,
1376                                     &type,
1377                                     GNUNET_NO,
1378                                     MYSQL_TYPE_LONG,
1379                                     &hops,
1380                                     GNUNET_YES,
1381                                     MYSQL_TYPE_LONGLONG,
1382                                     &key_uid,
1383                                     GNUNET_YES,
1384                                     MYSQL_TYPE_LONGLONG,
1385                                     &queryid,
1386                                     GNUNET_YES,
1387                                     MYSQL_TYPE_LONG,
1388                                     &succeeded,
1389                                     GNUNET_NO,
1390                                     MYSQL_TYPE_LONGLONG,
1391                                     &peer_uid,
1392                                     GNUNET_YES,
1393                                     MYSQL_TYPE_LONGLONG,
1394                                     &from_uid,
1395                                     GNUNET_YES,
1396                                     MYSQL_TYPE_LONGLONG,
1397                                     &to_uid, GNUNET_YES, -1)))
1398     {
1399       if (ret == GNUNET_SYSERR)
1400         {
1401           return GNUNET_SYSERR;
1402         }
1403     }
1404   if (ret > 0)
1405     return GNUNET_OK;
1406   else
1407     return GNUNET_SYSERR;
1408 }
1409
1410 /*
1411  * Update dhttests.topology table with total connections information
1412  *
1413  * @param totalConnections the number of connections
1414  *
1415  * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1416  */
1417 int
1418 update_current_topology (unsigned int connections)
1419 {
1420   int ret;
1421   unsigned long long topologyuid;
1422
1423   get_current_topology(&topologyuid);
1424
1425   if (GNUNET_OK !=
1426       (ret = prepared_statement_run (update_topology,
1427                                      NULL,
1428                                      MYSQL_TYPE_LONG,
1429                                      &connections,
1430                                      GNUNET_YES,
1431                                      MYSQL_TYPE_LONGLONG,
1432                                      &topologyuid, GNUNET_YES, -1)))
1433     {
1434       if (ret == GNUNET_SYSERR)
1435         {
1436           return GNUNET_SYSERR;
1437         }
1438     }
1439   if (ret > 0)
1440     return GNUNET_OK;
1441   else
1442     return GNUNET_SYSERR;
1443   return GNUNET_OK;
1444 }
1445
1446 /*
1447  * Records the current topology (number of connections, time, trial)
1448  *
1449  * @param num_connections how many connections are in the topology
1450  *
1451  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1452  */
1453 int
1454 add_topology (int num_connections)
1455 {
1456   int ret;
1457
1458   if (GNUNET_OK !=
1459       (ret = prepared_statement_run (insert_topology,
1460                                      NULL,
1461                                      MYSQL_TYPE_LONGLONG,
1462                                      &current_trial,
1463                                      GNUNET_YES,
1464                                      MYSQL_TYPE_LONG,
1465                                      &num_connections,
1466                                      GNUNET_YES, -1)))
1467     {
1468       if (ret == GNUNET_SYSERR)
1469         {
1470           return GNUNET_SYSERR;
1471         }
1472     }
1473   if (ret > 0)
1474     return GNUNET_OK;
1475   else
1476     return GNUNET_SYSERR;
1477   return GNUNET_OK;
1478 }
1479
1480 /*
1481  * Records a connection between two peers in the current topology
1482  *
1483  * @param first one side of the connection
1484  * @param second other side of the connection
1485  *
1486  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1487  */
1488 int
1489 add_extended_topology (const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second)
1490 {
1491   int ret;
1492   unsigned long long first_uid;
1493   unsigned long long second_uid;
1494   unsigned long long topologyuid;
1495
1496   if (GNUNET_OK != get_current_topology(&topologyuid))
1497     return GNUNET_SYSERR;
1498   if (GNUNET_OK != get_node_uid(&first_uid, &first->hashPubKey))
1499     return GNUNET_SYSERR;
1500   if (GNUNET_OK != get_node_uid(&second_uid, &second->hashPubKey))
1501     return GNUNET_SYSERR;
1502
1503   if (GNUNET_OK !=
1504       (ret = prepared_statement_run (extend_topology,
1505                                      NULL,
1506                                      MYSQL_TYPE_LONGLONG,
1507                                      &topologyuid,
1508                                      GNUNET_YES,
1509                                      MYSQL_TYPE_LONGLONG,
1510                                      &first_uid,
1511                                      GNUNET_YES,
1512                                      MYSQL_TYPE_LONGLONG,
1513                                      &second_uid,
1514                                      GNUNET_YES,-1)))
1515     {
1516       if (ret == GNUNET_SYSERR)
1517         {
1518           return GNUNET_SYSERR;
1519         }
1520     }
1521   if (ret > 0)
1522     return GNUNET_OK;
1523   else
1524     return GNUNET_SYSERR;
1525   return GNUNET_OK;
1526 }
1527
1528
1529 /*
1530  * Provides the dhtlog api
1531  *
1532  * @param c the configuration to use to connect to a server
1533  *
1534  * @return the handle to the server, or NULL on error
1535  */
1536 void *
1537 libgnunet_plugin_dhtlog_mysql_init (void * cls)
1538 {
1539   struct GNUNET_DHTLOG_Plugin *plugin = cls;
1540
1541   cfg = plugin->cfg;
1542   max_varchar_len = 255;
1543 #if DEBUG_DHTLOG
1544   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MySQL DHT Logger: initializing database\n");
1545 #endif
1546
1547   if (iopen (plugin) != GNUNET_OK)
1548     {
1549       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1550                   _("Failed to initialize MySQL database connection for dhtlog.\n"));
1551       return NULL;
1552     }
1553
1554   GNUNET_assert(plugin->dhtlog_api == NULL);
1555   plugin->dhtlog_api = GNUNET_malloc(sizeof(struct GNUNET_DHTLOG_Handle));
1556   plugin->dhtlog_api->insert_trial = &add_trial;
1557   plugin->dhtlog_api->insert_stat = &add_stat;
1558   plugin->dhtlog_api->add_generic_stat = &add_generic_stat;
1559   plugin->dhtlog_api->insert_query = &add_query;
1560   plugin->dhtlog_api->update_trial = &update_trials;
1561   plugin->dhtlog_api->insert_route = &add_route;
1562   plugin->dhtlog_api->insert_node = &add_node;
1563   plugin->dhtlog_api->insert_dhtkey = &add_dhtkey;
1564   plugin->dhtlog_api->update_connections = &add_connections;
1565   plugin->dhtlog_api->insert_topology = &add_topology;
1566   plugin->dhtlog_api->update_topology = &update_current_topology;
1567   plugin->dhtlog_api->insert_extended_topology = &add_extended_topology;
1568   plugin->dhtlog_api->set_malicious = &set_malicious;
1569   plugin->dhtlog_api->add_generic_stat = &add_generic_stat;
1570   get_current_trial (&current_trial);
1571
1572   return plugin;
1573 }
1574
1575 /**
1576  * Shutdown the plugin.
1577  */
1578 void *
1579 libgnunet_plugin_dhtlog_mysql_done (void * cls)
1580 {
1581   struct GNUNET_DHTLOG_Handle *dhtlog_api = cls;
1582
1583   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1584               "MySQL DHT Logger: database shutdown\n");
1585   GNUNET_assert(dhtlog_api != NULL);
1586   prepared_statement_close(insert_query);
1587   prepared_statement_close(insert_route);
1588   prepared_statement_close(insert_trial);
1589   prepared_statement_close(insert_node);
1590   prepared_statement_close(insert_dhtkey);
1591   prepared_statement_close(update_trial);
1592   prepared_statement_close(get_dhtkeyuid);
1593   prepared_statement_close(get_nodeuid);
1594   prepared_statement_close(update_connection);
1595   prepared_statement_close(get_trial);
1596   prepared_statement_close(get_topology);
1597   prepared_statement_close(insert_topology);
1598   prepared_statement_close(update_topology);
1599   prepared_statement_close(extend_topology);
1600   prepared_statement_close(update_node_malicious);
1601
1602   if (conn != NULL)
1603     mysql_close (conn);
1604   conn = NULL;
1605   mysql_library_end();
1606   GNUNET_free(dhtlog_api);
1607   return NULL;
1608 }
1609
1610 /* end of plugin_dhtlog_mysql.c */