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