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