diff options
author | Christian Grothoff <christian@grothoff.org> | 2011-09-27 20:47:21 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2011-09-27 20:47:21 +0000 |
commit | 18ad006e1f9b322d4760fb1473e8182f0d6ae7f0 (patch) | |
tree | b27c918b33f8ce5fa5651299c9f93ff6e963c3ed /src/dht | |
parent | 89bc96f3fc0509f872c8372caac099d81ed36622 (diff) | |
download | gnunet-18ad006e1f9b322d4760fb1473e8182f0d6ae7f0.tar.gz gnunet-18ad006e1f9b322d4760fb1473e8182f0d6ae7f0.zip |
DCE
Diffstat (limited to 'src/dht')
-rw-r--r-- | src/dht/Makefile.am | 70 | ||||
-rw-r--r-- | src/dht/dhtlog.c | 93 | ||||
-rw-r--r-- | src/dht/dhtlog.h | 394 | ||||
-rw-r--r-- | src/dht/gnunet-dht-get.c | 3 | ||||
-rw-r--r-- | src/dht/gnunet-service-dht.c | 4773 | ||||
-rw-r--r-- | src/dht/plugin_dhtlog_dummy.c | 347 | ||||
-rw-r--r-- | src/dht/plugin_dhtlog_mysql.c | 1612 | ||||
-rw-r--r-- | src/dht/plugin_dhtlog_mysql_dump.c | 964 |
8 files changed, 2 insertions, 8254 deletions
diff --git a/src/dht/Makefile.am b/src/dht/Makefile.am index 9f04943e5..147248234 100644 --- a/src/dht/Makefile.am +++ b/src/dht/Makefile.am | |||
@@ -5,10 +5,6 @@ endif | |||
5 | 5 | ||
6 | plugindir = $(libdir)/gnunet | 6 | plugindir = $(libdir)/gnunet |
7 | 7 | ||
8 | if HAVE_MYSQL | ||
9 | MYSQL_PLUGIN = libgnunet_plugin_dhtlog_mysql.la | ||
10 | endif | ||
11 | |||
12 | if HAVE_ZLIB | 8 | if HAVE_ZLIB |
13 | ZLIB_LNK = -lz | 9 | ZLIB_LNK = -lz |
14 | endif | 10 | endif |
@@ -20,56 +16,8 @@ endif | |||
20 | 16 | ||
21 | lib_LTLIBRARIES = \ | 17 | lib_LTLIBRARIES = \ |
22 | libgnunetdht.la \ | 18 | libgnunetdht.la \ |
23 | libgnunetdhtnew.la \ | 19 | libgnunetdhtnew.la |
24 | libgnunetdhtlog.la | ||
25 | |||
26 | plugin_LTLIBRARIES = \ | ||
27 | $(MYSQL_PLUGIN) \ | ||
28 | libgnunet_plugin_dhtlog_dummy.la \ | ||
29 | libgnunet_plugin_dhtlog_mysql_dump.la \ | ||
30 | libgnunet_plugin_dhtlog_mysql_dump_load.la | ||
31 | |||
32 | |||
33 | libgnunet_plugin_dhtlog_mysql_la_SOURCES = \ | ||
34 | plugin_dhtlog_mysql.c | ||
35 | libgnunet_plugin_dhtlog_mysql_la_LIBADD = \ | ||
36 | $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lz -lsqlite3 | ||
37 | libgnunet_plugin_dhtlog_mysql_la_LDFLAGS = \ | ||
38 | $(GN_PLUGIN_LDFLAGS) $(MYSQL_LDFLAGS) -lmysqlclient | ||
39 | libgnunet_plugin_dhtlog_mysql_la_CPFLAGS = \ | ||
40 | $(MYSQL_CPPFLAGS) | ||
41 | |||
42 | libgnunet_plugin_dhtlog_dummy_la_SOURCES = \ | ||
43 | plugin_dhtlog_dummy.c | ||
44 | libgnunet_plugin_dhtlog_dummy_la_LIBADD = \ | ||
45 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
46 | $(XLIB) | ||
47 | libgnunet_plugin_dhtlog_dummy_la_LDFLAGS = \ | ||
48 | $(GN_PLUGIN_LDFLAGS) | ||
49 | |||
50 | libgnunet_plugin_dhtlog_mysql_dump_la_SOURCES = \ | ||
51 | plugin_dhtlog_mysql_dump.c | ||
52 | libgnunet_plugin_dhtlog_mysql_dump_la_LIBADD = \ | ||
53 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
54 | $(XLIB) | ||
55 | libgnunet_plugin_dhtlog_mysql_dump_la_LDFLAGS = \ | ||
56 | $(GN_PLUGIN_LDFLAGS) | ||
57 | 20 | ||
58 | libgnunet_plugin_dhtlog_mysql_dump_load_la_SOURCES = \ | ||
59 | plugin_dhtlog_mysql_dump_load.c | ||
60 | libgnunet_plugin_dhtlog_mysql_dump_load_la_LIBADD = \ | ||
61 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
62 | $(XLIB) | ||
63 | libgnunet_plugin_dhtlog_mysql_dump_load_la_LDFLAGS = \ | ||
64 | $(GN_PLUGIN_LDFLAGS) | ||
65 | |||
66 | libgnunetdhtlog_la_SOURCES = \ | ||
67 | dhtlog.c dhtlog.h | ||
68 | libgnunetdhtlog_la_LIBADD = \ | ||
69 | $(top_builddir)/src/util/libgnunetutil.la | ||
70 | libgnunetdhtlog_la_LDFLAGS = \ | ||
71 | $(GN_LIB_LDFLAGS) $(WINFLAGS) \ | ||
72 | -version-info 0:0:0 | ||
73 | 21 | ||
74 | libgnunetdht_la_SOURCES = \ | 22 | libgnunetdht_la_SOURCES = \ |
75 | dht_api.c dht.h \ | 23 | dht_api.c dht.h \ |
@@ -92,7 +40,6 @@ libgnunetdhtnew_la_LDFLAGS = \ | |||
92 | -version-info 0:0:0 | 40 | -version-info 0:0:0 |
93 | 41 | ||
94 | bin_PROGRAMS = \ | 42 | bin_PROGRAMS = \ |
95 | gnunet-service-dht \ | ||
96 | gnunet-service-dht-new \ | 43 | gnunet-service-dht-new \ |
97 | gnunet-dht-get \ | 44 | gnunet-dht-get \ |
98 | gnunet-dht-put | 45 | gnunet-dht-put |
@@ -102,21 +49,6 @@ noinst_PROGRAMS = \ | |||
102 | gnunet-dht-driver | 49 | gnunet-dht-driver |
103 | endif | 50 | endif |
104 | 51 | ||
105 | gnunet_service_dht_SOURCES = \ | ||
106 | gnunet-service-dht.c | ||
107 | gnunet_service_dht_LDADD = \ | ||
108 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
109 | $(top_builddir)/src/core/libgnunetcore.la \ | ||
110 | $(top_builddir)/src/nse/libgnunetnse.la \ | ||
111 | $(top_builddir)/src/transport/libgnunettransport.la \ | ||
112 | $(top_builddir)/src/hello/libgnunethello.la \ | ||
113 | $(top_builddir)/src/block/libgnunetblock.la \ | ||
114 | $(top_builddir)/src/datacache/libgnunetdatacache.la \ | ||
115 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
116 | $(top_builddir)/src/dht/libgnunetdhtlog.la -lm | ||
117 | gnunet_service_dht_DEPENDENCIES = \ | ||
118 | libgnunetdhtlog.la | ||
119 | |||
120 | gnunet_service_dht_new_SOURCES = \ | 52 | gnunet_service_dht_new_SOURCES = \ |
121 | gnunet-service-dht-new.c gnunet-service-dht.h \ | 53 | gnunet-service-dht-new.c gnunet-service-dht.h \ |
122 | gnunet-service-dht_clients.c gnunet-service-dht_clients.h \ | 54 | gnunet-service-dht_clients.c gnunet-service-dht_clients.h \ |
diff --git a/src/dht/dhtlog.c b/src/dht/dhtlog.c deleted file mode 100644 index d56ba6469..000000000 --- a/src/dht/dhtlog.c +++ /dev/null | |||
@@ -1,93 +0,0 @@ | |||
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/dhtlog.c | ||
23 | * @brief Plugin loaded to load logging | ||
24 | * to record DHT operations | ||
25 | * @author Nathan Evans | ||
26 | * | ||
27 | * Database: Loaded by plugin MySQL | ||
28 | */ | ||
29 | |||
30 | #include "platform.h" | ||
31 | #include "gnunet_util_lib.h" | ||
32 | #include "dhtlog.h" | ||
33 | |||
34 | static char *libname; | ||
35 | |||
36 | /* | ||
37 | * Provides the dhtlog api | ||
38 | * | ||
39 | * @param c the configuration to use to connect to a server | ||
40 | * | ||
41 | * @return the handle to the server, or NULL on error | ||
42 | */ | ||
43 | struct GNUNET_DHTLOG_Handle * | ||
44 | GNUNET_DHTLOG_connect (const struct GNUNET_CONFIGURATION_Handle *c) | ||
45 | { | ||
46 | struct GNUNET_DHTLOG_Plugin *plugin; | ||
47 | struct GNUNET_DHTLOG_Handle *api; | ||
48 | char *plugin_name; | ||
49 | |||
50 | plugin = GNUNET_malloc (sizeof (struct GNUNET_DHTLOG_Plugin)); | ||
51 | plugin->cfg = c; | ||
52 | if (GNUNET_OK == | ||
53 | GNUNET_CONFIGURATION_get_value_string (c, "DHTLOG", "PLUGIN", | ||
54 | &plugin_name)) | ||
55 | { | ||
56 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading `%s' dhtlog plugin\n"), | ||
57 | plugin_name); | ||
58 | GNUNET_asprintf (&libname, "libgnunet_plugin_dhtlog_%s", plugin_name); | ||
59 | GNUNET_PLUGIN_load (libname, plugin); | ||
60 | } | ||
61 | |||
62 | if (plugin->dhtlog_api == NULL) | ||
63 | { | ||
64 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
65 | _("Failed to load dhtlog plugin for `%s'\n"), plugin_name); | ||
66 | GNUNET_free (plugin_name); | ||
67 | GNUNET_free (plugin); | ||
68 | return NULL; | ||
69 | } | ||
70 | |||
71 | api = plugin->dhtlog_api; | ||
72 | GNUNET_free (plugin_name); | ||
73 | GNUNET_free (plugin); | ||
74 | return api; | ||
75 | } | ||
76 | |||
77 | /** | ||
78 | * Shutdown the module. | ||
79 | */ | ||
80 | void | ||
81 | GNUNET_DHTLOG_disconnect (struct GNUNET_DHTLOG_Handle *api) | ||
82 | { | ||
83 | #if DEBUG_DHTLOG | ||
84 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MySQL DHT Logger: database shutdown\n"); | ||
85 | #endif | ||
86 | if (api != NULL) | ||
87 | { | ||
88 | GNUNET_PLUGIN_unload (libname, api); | ||
89 | } | ||
90 | GNUNET_free_non_null (libname); | ||
91 | } | ||
92 | |||
93 | /* end of dhtlog.c */ | ||
diff --git a/src/dht/dhtlog.h b/src/dht/dhtlog.h deleted file mode 100644 index cdab36305..000000000 --- a/src/dht/dhtlog.h +++ /dev/null | |||
@@ -1,394 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | (C) 2006 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/dhtlog.h | ||
23 | * | ||
24 | * @brief dhtlog is a service that implements logging of dht operations | ||
25 | * for testing | ||
26 | * @author Nathan Evans | ||
27 | */ | ||
28 | |||
29 | #ifndef GNUNET_DHTLOG_SERVICE_H | ||
30 | #define GNUNET_DHTLOG_SERVICE_H | ||
31 | |||
32 | #include "gnunet_util_lib.h" | ||
33 | |||
34 | #ifdef __cplusplus | ||
35 | extern "C" | ||
36 | { | ||
37 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
38 | } | ||
39 | #endif | ||
40 | #endif | ||
41 | |||
42 | typedef enum | ||
43 | { | ||
44 | /** | ||
45 | * Type for a DHT GET message | ||
46 | */ | ||
47 | DHTLOG_GET = 1, | ||
48 | |||
49 | /** | ||
50 | * Type for a DHT PUT message | ||
51 | */ | ||
52 | DHTLOG_PUT = 2, | ||
53 | |||
54 | /** | ||
55 | * Type for a DHT FIND PEER message | ||
56 | */ | ||
57 | DHTLOG_FIND_PEER = 3, | ||
58 | |||
59 | /** | ||
60 | * Type for a DHT RESULT message | ||
61 | */ | ||
62 | DHTLOG_RESULT = 4, | ||
63 | |||
64 | /** | ||
65 | * Generic DHT ROUTE message | ||
66 | */ | ||
67 | DHTLOG_ROUTE = 5, | ||
68 | |||
69 | } DHTLOG_MESSAGE_TYPES; | ||
70 | |||
71 | struct GNUNET_DHTLOG_TrialInfo | ||
72 | { | ||
73 | /** | ||
74 | * Outside of database identifier for the trial. | ||
75 | */ | ||
76 | unsigned int other_identifier; | ||
77 | |||
78 | /** Number of nodes in the trial */ | ||
79 | unsigned int num_nodes; | ||
80 | |||
81 | /** Type of initial topology */ | ||
82 | unsigned int topology; | ||
83 | |||
84 | /** Topology to blacklist peers to */ | ||
85 | unsigned int blacklist_topology; | ||
86 | |||
87 | /** Initially connect peers in this topology */ | ||
88 | unsigned int connect_topology; | ||
89 | |||
90 | /** Option to modify connect topology */ | ||
91 | unsigned int connect_topology_option; | ||
92 | |||
93 | /** Modifier for the connect option */ | ||
94 | float connect_topology_option_modifier; | ||
95 | |||
96 | /** Percentage parameter used for certain topologies */ | ||
97 | float topology_percentage; | ||
98 | |||
99 | /** Probability parameter used for certain topologies */ | ||
100 | float topology_probability; | ||
101 | |||
102 | /** Number of puts in the trial */ | ||
103 | unsigned int puts; | ||
104 | |||
105 | /** Number of gets in the trial */ | ||
106 | unsigned int gets; | ||
107 | |||
108 | /** Concurrent puts/gets in the trial (max allowed) */ | ||
109 | unsigned int concurrent; | ||
110 | |||
111 | /** How long between initial connection and issuing puts/gets */ | ||
112 | unsigned int settle_time; | ||
113 | |||
114 | /** How many times to do put/get loop */ | ||
115 | unsigned int num_rounds; | ||
116 | |||
117 | /** Number of malicious getters */ | ||
118 | unsigned int malicious_getters; | ||
119 | |||
120 | /** Number of malicious putters */ | ||
121 | unsigned int malicious_putters; | ||
122 | |||
123 | /** Number of malicious droppers */ | ||
124 | unsigned int malicious_droppers; | ||
125 | |||
126 | /** Frequency of malicious get requests */ | ||
127 | unsigned int malicious_get_frequency; | ||
128 | |||
129 | /** Frequency of malicious put requests */ | ||
130 | unsigned int malicious_put_frequency; | ||
131 | |||
132 | /** Stop forwarding put/find_peer requests when peer is closer than others */ | ||
133 | unsigned int stop_closest; | ||
134 | |||
135 | /** Stop forwarding get requests when data found */ | ||
136 | unsigned int stop_found; | ||
137 | |||
138 | /** | ||
139 | * Routing behaves as it would in Kademlia (modified to work recursively, | ||
140 | * and with our other GNUnet constraints). | ||
141 | */ | ||
142 | unsigned int strict_kademlia; | ||
143 | |||
144 | /** Number of gets that were reported successful */ | ||
145 | unsigned int gets_succeeded; | ||
146 | |||
147 | /** Message for this trial */ | ||
148 | char *message; | ||
149 | }; | ||
150 | |||
151 | struct GNUNET_DHTLOG_Handle | ||
152 | { | ||
153 | |||
154 | /* | ||
155 | * Inserts the specified query into the dhttests.queries table | ||
156 | * | ||
157 | * @param sqlqueruid inserted query uid | ||
158 | * @param queryid dht query id | ||
159 | * @param type type of the query | ||
160 | * @param hops number of hops query traveled | ||
161 | * @param succeeded whether or not query was successful | ||
162 | * @param node the node the query hit | ||
163 | * @param key the key of the query | ||
164 | * | ||
165 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure. | ||
166 | */ | ||
167 | int (*insert_query) (unsigned long long *sqlqueryuid, | ||
168 | unsigned long long queryid, DHTLOG_MESSAGE_TYPES type, | ||
169 | unsigned int hops, int succeeded, | ||
170 | const struct GNUNET_PeerIdentity * node, | ||
171 | const GNUNET_HashCode * key); | ||
172 | |||
173 | /* | ||
174 | * Inserts the specified trial into the dhttests.trials table | ||
175 | * | ||
176 | * @param trial_info general information about this trial | ||
177 | * | ||
178 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
179 | */ | ||
180 | int (*insert_trial) (struct GNUNET_DHTLOG_TrialInfo * trial_info); | ||
181 | |||
182 | /* | ||
183 | * Inserts the specified stats into the dhttests.node_statistics table | ||
184 | * | ||
185 | * @param peer the peer inserting the statistic | ||
186 | * @param route_requests route requests seen | ||
187 | * @param route_forwards route requests forwarded | ||
188 | * @param result_requests route result requests seen | ||
189 | * @param client_requests client requests initiated | ||
190 | * @param result_forwards route results forwarded | ||
191 | * @param gets get requests handled | ||
192 | * @param puts put requests handle | ||
193 | * @param data_inserts data inserted at this node | ||
194 | * @param find_peer_requests find peer requests seen | ||
195 | * @param find_peers_started find peer requests initiated at this node | ||
196 | * @param gets_started get requests initiated at this node | ||
197 | * @param puts_started put requests initiated at this node | ||
198 | * @param find_peer_responses_received find peer responses received locally | ||
199 | * @param get_responses_received get responses received locally | ||
200 | * @param find_peer_responses_sent find peer responses sent from this node | ||
201 | * @param get_responses_sent get responses sent from this node | ||
202 | * | ||
203 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
204 | */ | ||
205 | int (*insert_stat) (const struct GNUNET_PeerIdentity * peer, | ||
206 | unsigned int route_requests, unsigned int route_forwards, | ||
207 | unsigned int result_requests, | ||
208 | unsigned int client_requests, | ||
209 | unsigned int result_forwards, unsigned int gets, | ||
210 | unsigned int puts, unsigned int data_inserts, | ||
211 | unsigned int find_peer_requests, | ||
212 | unsigned int find_peers_started, | ||
213 | unsigned int gets_started, unsigned int puts_started, | ||
214 | unsigned int find_peer_responses_received, | ||
215 | unsigned int get_responses_received, | ||
216 | unsigned int find_peer_responses_sent, | ||
217 | unsigned int get_responses_sent); | ||
218 | |||
219 | /* | ||
220 | * Update dhttests.trials table with current server time as end time | ||
221 | * | ||
222 | * @param gets_succeeded how many gets did the trial report successful | ||
223 | * | ||
224 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure. | ||
225 | */ | ||
226 | int (*update_trial) (unsigned int gets_succeeded); | ||
227 | |||
228 | /* | ||
229 | * Update dhttests.nodes table setting the identified | ||
230 | * node as a malicious dropper. | ||
231 | * | ||
232 | * @param peer the peer that was set to be malicious | ||
233 | * | ||
234 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure. | ||
235 | */ | ||
236 | int (*set_malicious) (struct GNUNET_PeerIdentity * peer); | ||
237 | |||
238 | /* | ||
239 | * Records the current topology (number of connections, time, trial) | ||
240 | * | ||
241 | * @param num_connections how many connections are in the topology | ||
242 | * | ||
243 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
244 | */ | ||
245 | int (*insert_topology) (int num_connections); | ||
246 | |||
247 | /* | ||
248 | * Records a connection between two peers in the current topology | ||
249 | * | ||
250 | * @param first one side of the connection | ||
251 | * @param second other side of the connection | ||
252 | * | ||
253 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
254 | */ | ||
255 | int (*insert_extended_topology) (const struct GNUNET_PeerIdentity * first, | ||
256 | const struct GNUNET_PeerIdentity * second); | ||
257 | |||
258 | /* | ||
259 | * Inserts the specified stats into the dhttests.generic_stats table | ||
260 | * | ||
261 | * @param peer the peer inserting the statistic | ||
262 | * @param name the name of the statistic | ||
263 | * @param section the section of the statistic | ||
264 | * @param value the value of the statistic | ||
265 | * | ||
266 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
267 | */ | ||
268 | int (*add_generic_stat) (const struct GNUNET_PeerIdentity * peer, | ||
269 | const char *name, const char *section, | ||
270 | uint64_t value); | ||
271 | |||
272 | /* | ||
273 | * Inserts the specified round into the dhttests.rounds table | ||
274 | * | ||
275 | * @param round_type the type of round that is being started | ||
276 | * @param round_count counter for the round (if applicable) | ||
277 | * | ||
278 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
279 | */ | ||
280 | int (*insert_round) (unsigned int round_type, unsigned int round_count); | ||
281 | |||
282 | /* | ||
283 | * Inserts the specified round results into the | ||
284 | * dhttests.processed_round_details table | ||
285 | * | ||
286 | * @param round_type the type of round that is being started | ||
287 | * @param round_count counter for the round (if applicable) | ||
288 | * @param num_messages the total number of messages initiated | ||
289 | * @param num_messages_succeeded the number of messages that succeeded | ||
290 | * | ||
291 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
292 | */ | ||
293 | int (*insert_round_details) (unsigned int round_type, | ||
294 | unsigned int round_count, | ||
295 | unsigned int num_messages, | ||
296 | unsigned int num_messages_succeeded); | ||
297 | |||
298 | /* | ||
299 | * Update dhttests.trials table with total connections information | ||
300 | * | ||
301 | * @param totalConnections the number of connections | ||
302 | * | ||
303 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure. | ||
304 | */ | ||
305 | int (*update_connections) (unsigned int totalConnections); | ||
306 | |||
307 | /* | ||
308 | * Update dhttests.trials table with total connections information | ||
309 | * | ||
310 | * @param connections the number of connections | ||
311 | * | ||
312 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure. | ||
313 | */ | ||
314 | int (*update_topology) (unsigned int connections); | ||
315 | |||
316 | /* | ||
317 | * Inserts the specified route information into the dhttests.routes table | ||
318 | * | ||
319 | * @param sqlqueruid inserted query uid | ||
320 | * @param queryid dht query id | ||
321 | * @param type type of the query | ||
322 | * @param hops number of hops query traveled | ||
323 | * @param succeeded whether or not query was successful | ||
324 | * @param node the node the query hit | ||
325 | * @param key the key of the query | ||
326 | * @param from_node the node that sent the message to node | ||
327 | * @param to_node next node to forward message to | ||
328 | * | ||
329 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure. | ||
330 | */ | ||
331 | int (*insert_route) (unsigned long long *sqlqueryuid, | ||
332 | unsigned long long queryid, unsigned int type, | ||
333 | unsigned int hops, int succeeded, | ||
334 | const struct GNUNET_PeerIdentity * node, | ||
335 | const GNUNET_HashCode * key, | ||
336 | const struct GNUNET_PeerIdentity * from_node, | ||
337 | const struct GNUNET_PeerIdentity * to_node); | ||
338 | |||
339 | /* | ||
340 | * Inserts the specified node into the dhttests.nodes table | ||
341 | * | ||
342 | * @param nodeuid the inserted node uid | ||
343 | * @param node the node to insert | ||
344 | * | ||
345 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
346 | */ | ||
347 | int (*insert_node) (unsigned long long *nodeuid, | ||
348 | struct GNUNET_PeerIdentity * node); | ||
349 | |||
350 | /* | ||
351 | * Inserts the specified dhtkey into the dhttests.dhtkeys table, | ||
352 | * stores return value of dhttests.dhtkeys.dhtkeyuid into dhtkeyuid | ||
353 | * | ||
354 | * @param dhtkeyuid return value | ||
355 | * @param dhtkey hashcode of key to insert | ||
356 | * | ||
357 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
358 | */ | ||
359 | int (*insert_dhtkey) (unsigned long long *dhtkeyuid, | ||
360 | const GNUNET_HashCode * dhtkey); | ||
361 | |||
362 | }; | ||
363 | |||
364 | struct GNUNET_DHTLOG_Plugin | ||
365 | { | ||
366 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
367 | |||
368 | struct GNUNET_DHTLOG_Handle *dhtlog_api; | ||
369 | }; | ||
370 | |||
371 | /** | ||
372 | * Connect to mysql server using the DHT log plugin. | ||
373 | * | ||
374 | * @param c a configuration to use | ||
375 | */ | ||
376 | struct GNUNET_DHTLOG_Handle * | ||
377 | GNUNET_DHTLOG_connect (const struct GNUNET_CONFIGURATION_Handle *c); | ||
378 | |||
379 | /** | ||
380 | * Shutdown the module. | ||
381 | */ | ||
382 | void | ||
383 | GNUNET_DHTLOG_disconnect (struct GNUNET_DHTLOG_Handle *api); | ||
384 | |||
385 | |||
386 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
387 | { | ||
388 | #endif | ||
389 | #ifdef __cplusplus | ||
390 | } | ||
391 | #endif | ||
392 | |||
393 | /* end of dhtlog.h */ | ||
394 | #endif | ||
diff --git a/src/dht/gnunet-dht-get.c b/src/dht/gnunet-dht-get.c index 1e75a742a..0d291e5e7 100644 --- a/src/dht/gnunet-dht-get.c +++ b/src/dht/gnunet-dht-get.c | |||
@@ -61,7 +61,6 @@ static int verbose; | |||
61 | */ | 61 | */ |
62 | static struct GNUNET_DHT_Handle *dht_handle; | 62 | static struct GNUNET_DHT_Handle *dht_handle; |
63 | 63 | ||
64 | |||
65 | /** | 64 | /** |
66 | * Global handle of the configuration | 65 | * Global handle of the configuration |
67 | */ | 66 | */ |
@@ -121,7 +120,7 @@ cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
121 | * @param size number of bytes in data | 120 | * @param size number of bytes in data |
122 | * @param data pointer to the result data | 121 | * @param data pointer to the result data |
123 | */ | 122 | */ |
124 | void | 123 | static void |
125 | get_result_iterator (void *cls, struct GNUNET_TIME_Absolute exp, | 124 | get_result_iterator (void *cls, struct GNUNET_TIME_Absolute exp, |
126 | const GNUNET_HashCode * key, | 125 | const GNUNET_HashCode * key, |
127 | const struct GNUNET_PeerIdentity *get_path, | 126 | const struct GNUNET_PeerIdentity *get_path, |
diff --git a/src/dht/gnunet-service-dht.c b/src/dht/gnunet-service-dht.c deleted file mode 100644 index 2650baeb2..000000000 --- a/src/dht/gnunet-service-dht.c +++ /dev/null | |||
@@ -1,4773 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009, 2010, 2011 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 3, 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 dht/gnunet-service-dht.c | ||
23 | * @brief GNUnet DHT service | ||
24 | * @author Christian Grothoff | ||
25 | * @author Nathan Evans | ||
26 | * | ||
27 | * TODO: | ||
28 | * - decide which 'benchmark'/test functions to keep (malicious code, kademlia, etc.) | ||
29 | * - decide on 'stop_on_closest', 'stop_on_found', 'do_find_peer', 'paper_forwarding' | ||
30 | * - use OPTION_MULTIPLE instead of linked list for the forward_list.hashmap | ||
31 | * - use different 'struct DHT_MessageContext' for the different types of | ||
32 | * messages (currently rather confusing, especially with things like | ||
33 | * peer bloom filters occuring when processing replies). | ||
34 | * - why do we have request UIDs again? | ||
35 | */ | ||
36 | |||
37 | #include "platform.h" | ||
38 | #include "gnunet_block_lib.h" | ||
39 | #include "gnunet_constants.h" | ||
40 | #include "gnunet_protocols.h" | ||
41 | #include "gnunet_nse_service.h" | ||
42 | #include "gnunet_core_service.h" | ||
43 | #include "gnunet_util_lib.h" | ||
44 | #include "gnunet_datacache_lib.h" | ||
45 | #include "gnunet_transport_service.h" | ||
46 | #include "gnunet_hello_lib.h" | ||
47 | #include "gnunet_dht_service.h" | ||
48 | #include "gnunet_statistics_service.h" | ||
49 | #include "dhtlog.h" | ||
50 | #include "dht.h" | ||
51 | #include <fenv.h> | ||
52 | |||
53 | |||
54 | /** | ||
55 | * How many buckets will we allow total. | ||
56 | */ | ||
57 | #define MAX_BUCKETS sizeof (GNUNET_HashCode) * 8 | ||
58 | |||
59 | /** | ||
60 | * Should the DHT issue FIND_PEER requests to get better routing tables? | ||
61 | */ | ||
62 | #define DEFAULT_DO_FIND_PEER GNUNET_YES | ||
63 | |||
64 | /** | ||
65 | * Defines whether find peer requests send their HELLO's outgoing, | ||
66 | * or expect replies to contain hellos. | ||
67 | */ | ||
68 | #define FIND_PEER_WITH_HELLO GNUNET_YES | ||
69 | |||
70 | /** | ||
71 | * What is the maximum number of peers in a given bucket. | ||
72 | */ | ||
73 | #define DEFAULT_BUCKET_SIZE 4 | ||
74 | |||
75 | #define DEFAULT_CORE_QUEUE_SIZE 32 | ||
76 | |||
77 | /** | ||
78 | * Minimum number of peers we need for "good" routing, | ||
79 | * any less than this and we will allow messages to | ||
80 | * travel much further through the network! | ||
81 | */ | ||
82 | #define MINIMUM_PEER_THRESHOLD 20 | ||
83 | |||
84 | /** | ||
85 | * Number of requests we track at most (for routing replies). | ||
86 | */ | ||
87 | #define DHT_MAX_RECENT (1024 * 16) | ||
88 | |||
89 | /** | ||
90 | * How long do we wait at most when queueing messages with core | ||
91 | * that we are sending on behalf of other peers. | ||
92 | */ | ||
93 | #define DHT_DEFAULT_P2P_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) | ||
94 | |||
95 | /** | ||
96 | * Default importance for handling messages on behalf of other peers. | ||
97 | */ | ||
98 | #define DHT_DEFAULT_P2P_IMPORTANCE 0 | ||
99 | |||
100 | /** | ||
101 | * How long to keep recent requests around by default. | ||
102 | */ | ||
103 | #define DEFAULT_RECENT_REMOVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) | ||
104 | |||
105 | /** | ||
106 | * Default time to wait to send find peer messages sent by the dht service. | ||
107 | */ | ||
108 | #define DHT_DEFAULT_FIND_PEER_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) | ||
109 | |||
110 | /** | ||
111 | * Default importance for find peer messages sent by the dht service. | ||
112 | */ | ||
113 | #define DHT_DEFAULT_FIND_PEER_IMPORTANCE 8 | ||
114 | |||
115 | /** | ||
116 | * Default replication parameter for find peer messages sent by the dht service. | ||
117 | */ | ||
118 | #define DHT_DEFAULT_FIND_PEER_REPLICATION 4 | ||
119 | |||
120 | /** | ||
121 | * How long at least to wait before sending another find peer request. | ||
122 | */ | ||
123 | #define DHT_MINIMUM_FIND_PEER_INTERVAL GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2) | ||
124 | |||
125 | /** | ||
126 | * How long at most to wait before sending another find peer request. | ||
127 | */ | ||
128 | #define DHT_MAXIMUM_FIND_PEER_INTERVAL GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 8) | ||
129 | |||
130 | /** | ||
131 | * How often to update our preference levels for peers in our routing tables. | ||
132 | */ | ||
133 | #define DHT_DEFAULT_PREFERENCE_INTERVAL GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2) | ||
134 | |||
135 | /** | ||
136 | * How long at most on average will we allow a reply forward to take | ||
137 | * (before we quit sending out new requests) | ||
138 | */ | ||
139 | #define MAX_REQUEST_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) | ||
140 | |||
141 | /** | ||
142 | * How many initial requests to send out (in true Kademlia fashion) | ||
143 | */ | ||
144 | #define DEFAULT_KADEMLIA_REPLICATION 3 | ||
145 | |||
146 | /** | ||
147 | * Default frequency for sending malicious get messages | ||
148 | */ | ||
149 | #define DEFAULT_MALICIOUS_GET_FREQUENCY GNUNET_TIME_UNIT_SECONDS | ||
150 | |||
151 | /** | ||
152 | * Default frequency for sending malicious put messages | ||
153 | */ | ||
154 | #define DEFAULT_MALICIOUS_PUT_FREQUENCY GNUNET_TIME_UNIT_SECONDS | ||
155 | |||
156 | /** | ||
157 | * How many time differences between requesting a core send and | ||
158 | * the actual callback to remember. | ||
159 | */ | ||
160 | #define MAX_REPLY_TIMES 8 | ||
161 | |||
162 | |||
163 | /** | ||
164 | * Linked list of messages to send to clients. | ||
165 | */ | ||
166 | struct P2PPendingMessage | ||
167 | { | ||
168 | /** | ||
169 | * Pointer to next item in the list | ||
170 | */ | ||
171 | struct P2PPendingMessage *next; | ||
172 | |||
173 | /** | ||
174 | * Pointer to previous item in the list | ||
175 | */ | ||
176 | struct P2PPendingMessage *prev; | ||
177 | |||
178 | /** | ||
179 | * Message importance level. | ||
180 | */ | ||
181 | unsigned int importance; | ||
182 | |||
183 | /** | ||
184 | * Time when this request was scheduled to be sent. | ||
185 | */ | ||
186 | struct GNUNET_TIME_Absolute scheduled; | ||
187 | |||
188 | /** | ||
189 | * How long to wait before sending message. | ||
190 | */ | ||
191 | struct GNUNET_TIME_Relative timeout; | ||
192 | |||
193 | /** | ||
194 | * Actual message to be sent; // avoid allocation | ||
195 | */ | ||
196 | const struct GNUNET_MessageHeader *msg; // msg = (cast) &pm[1]; // memcpy (&pm[1], data, len); | ||
197 | |||
198 | }; | ||
199 | |||
200 | |||
201 | /** | ||
202 | * Per-peer information. | ||
203 | */ | ||
204 | struct PeerInfo | ||
205 | { | ||
206 | /** | ||
207 | * Next peer entry (DLL) | ||
208 | */ | ||
209 | struct PeerInfo *next; | ||
210 | |||
211 | /** | ||
212 | * Prev peer entry (DLL) | ||
213 | */ | ||
214 | struct PeerInfo *prev; | ||
215 | |||
216 | /** | ||
217 | * Count of outstanding messages for peer. | ||
218 | */ | ||
219 | unsigned int pending_count; | ||
220 | |||
221 | /** | ||
222 | * Head of pending messages to be sent to this peer. | ||
223 | */ | ||
224 | struct P2PPendingMessage *head; | ||
225 | |||
226 | /** | ||
227 | * Tail of pending messages to be sent to this peer. | ||
228 | */ | ||
229 | struct P2PPendingMessage *tail; | ||
230 | |||
231 | /** | ||
232 | * Core handle for sending messages to this peer. | ||
233 | */ | ||
234 | struct GNUNET_CORE_TransmitHandle *th; | ||
235 | |||
236 | /** | ||
237 | * Task for scheduling message sends. | ||
238 | */ | ||
239 | GNUNET_SCHEDULER_TaskIdentifier send_task; | ||
240 | |||
241 | /** | ||
242 | * Task for scheduling preference updates | ||
243 | */ | ||
244 | GNUNET_SCHEDULER_TaskIdentifier preference_task; | ||
245 | |||
246 | /** | ||
247 | * Preference update context | ||
248 | */ | ||
249 | struct GNUNET_CORE_InformationRequestContext *info_ctx; | ||
250 | |||
251 | /** | ||
252 | * What is the identity of the peer? | ||
253 | */ | ||
254 | struct GNUNET_PeerIdentity id; | ||
255 | |||
256 | #if 0 | ||
257 | /** | ||
258 | * What is the average latency for replies received? | ||
259 | */ | ||
260 | struct GNUNET_TIME_Relative latency; | ||
261 | |||
262 | /** | ||
263 | * Transport level distance to peer. | ||
264 | */ | ||
265 | unsigned int distance; | ||
266 | #endif | ||
267 | |||
268 | /** | ||
269 | * Task for scheduling periodic ping messages for this peer. | ||
270 | */ | ||
271 | GNUNET_SCHEDULER_TaskIdentifier ping_task; | ||
272 | }; | ||
273 | |||
274 | |||
275 | /** | ||
276 | * Peers are grouped into buckets. | ||
277 | */ | ||
278 | struct PeerBucket | ||
279 | { | ||
280 | /** | ||
281 | * Head of DLL | ||
282 | */ | ||
283 | struct PeerInfo *head; | ||
284 | |||
285 | /** | ||
286 | * Tail of DLL | ||
287 | */ | ||
288 | struct PeerInfo *tail; | ||
289 | |||
290 | /** | ||
291 | * Number of peers in the bucket. | ||
292 | */ | ||
293 | unsigned int peers_size; | ||
294 | }; | ||
295 | |||
296 | |||
297 | /** | ||
298 | * Linked list of messages to send to clients. | ||
299 | */ | ||
300 | struct PendingMessage | ||
301 | { | ||
302 | /** | ||
303 | * Pointer to next item in the list | ||
304 | */ | ||
305 | struct PendingMessage *next; | ||
306 | |||
307 | /** | ||
308 | * Pointer to previous item in the list | ||
309 | */ | ||
310 | struct PendingMessage *prev; | ||
311 | |||
312 | /** | ||
313 | * Actual message to be sent; // avoid allocation | ||
314 | */ | ||
315 | const struct GNUNET_MessageHeader *msg; // msg = (cast) &pm[1]; // memcpy (&pm[1], data, len); | ||
316 | |||
317 | }; | ||
318 | |||
319 | |||
320 | /** | ||
321 | * Struct containing information about a client, | ||
322 | * handle to connect to it, and any pending messages | ||
323 | * that need to be sent to it. | ||
324 | */ | ||
325 | struct ClientList | ||
326 | { | ||
327 | /** | ||
328 | * Linked list of active clients | ||
329 | */ | ||
330 | struct ClientList *next; | ||
331 | |||
332 | /** | ||
333 | * The handle to this client | ||
334 | */ | ||
335 | struct GNUNET_SERVER_Client *client_handle; | ||
336 | |||
337 | /** | ||
338 | * Handle to the current transmission request, NULL | ||
339 | * if none pending. | ||
340 | */ | ||
341 | struct GNUNET_CONNECTION_TransmitHandle *transmit_handle; | ||
342 | |||
343 | /** | ||
344 | * Linked list of pending messages for this client | ||
345 | */ | ||
346 | struct PendingMessage *pending_head; | ||
347 | |||
348 | /** | ||
349 | * Tail of linked list of pending messages for this client | ||
350 | */ | ||
351 | struct PendingMessage *pending_tail; | ||
352 | }; | ||
353 | |||
354 | |||
355 | /** | ||
356 | * Context containing information about a DHT message received. | ||
357 | */ | ||
358 | struct DHT_MessageContext | ||
359 | { | ||
360 | /** | ||
361 | * The client this request was received from. | ||
362 | * (NULL if received from another peer) | ||
363 | */ | ||
364 | struct ClientList *client; | ||
365 | |||
366 | /** | ||
367 | * The peer this request was received from. | ||
368 | */ | ||
369 | struct GNUNET_PeerIdentity peer; | ||
370 | |||
371 | /** | ||
372 | * Bloomfilter for this routing request. | ||
373 | */ | ||
374 | struct GNUNET_CONTAINER_BloomFilter *bloom; | ||
375 | |||
376 | /** | ||
377 | * extended query (see gnunet_block_lib.h). | ||
378 | */ | ||
379 | const void *xquery; | ||
380 | |||
381 | /** | ||
382 | * Bloomfilter to filter out duplicate replies. | ||
383 | */ | ||
384 | struct GNUNET_CONTAINER_BloomFilter *reply_bf; | ||
385 | |||
386 | /** | ||
387 | * The key this request was about | ||
388 | */ | ||
389 | GNUNET_HashCode key; | ||
390 | |||
391 | /** | ||
392 | * How long should we wait to transmit this request? | ||
393 | */ | ||
394 | struct GNUNET_TIME_Relative timeout; | ||
395 | |||
396 | /** | ||
397 | * The unique identifier of this request | ||
398 | */ | ||
399 | uint64_t unique_id; | ||
400 | |||
401 | /** | ||
402 | * Number of bytes in xquery. | ||
403 | */ | ||
404 | size_t xquery_size; | ||
405 | |||
406 | /** | ||
407 | * Mutator value for the reply_bf, see gnunet_block_lib.h | ||
408 | */ | ||
409 | uint32_t reply_bf_mutator; | ||
410 | |||
411 | /** | ||
412 | * Desired replication level | ||
413 | */ | ||
414 | uint32_t replication; | ||
415 | |||
416 | /** | ||
417 | * Network size estimate, either ours or the sum of | ||
418 | * those routed to thus far. =~ Log of number of peers | ||
419 | * chosen from for this request. | ||
420 | */ | ||
421 | uint32_t network_size; | ||
422 | |||
423 | /** | ||
424 | * Any message options for this request | ||
425 | */ | ||
426 | uint32_t msg_options; | ||
427 | |||
428 | /** | ||
429 | * How many hops has the message already traversed? | ||
430 | */ | ||
431 | uint32_t hop_count; | ||
432 | |||
433 | /** | ||
434 | * How many peer identities are present in the path history? | ||
435 | */ | ||
436 | uint32_t path_history_len; | ||
437 | |||
438 | /** | ||
439 | * Path history. | ||
440 | */ | ||
441 | char *path_history; | ||
442 | |||
443 | /** | ||
444 | * How important is this message? | ||
445 | */ | ||
446 | unsigned int importance; | ||
447 | |||
448 | /** | ||
449 | * Should we (still) forward the request on to other peers? | ||
450 | */ | ||
451 | int do_forward; | ||
452 | |||
453 | /** | ||
454 | * Did we forward this message? (may need to remember it!) | ||
455 | */ | ||
456 | int forwarded; | ||
457 | |||
458 | /** | ||
459 | * Are we the closest known peer to this key (out of our neighbors?) | ||
460 | */ | ||
461 | int closest; | ||
462 | }; | ||
463 | |||
464 | |||
465 | /** | ||
466 | * Record used for remembering what peers are waiting for what | ||
467 | * responses (based on search key). | ||
468 | */ | ||
469 | struct DHTRouteSource | ||
470 | { | ||
471 | /** | ||
472 | * This is a DLL. | ||
473 | */ | ||
474 | struct DHTRouteSource *next; | ||
475 | |||
476 | /** | ||
477 | * This is a DLL. | ||
478 | */ | ||
479 | struct DHTRouteSource *prev; | ||
480 | |||
481 | /** | ||
482 | * UID of the request, 0 if from another peer. | ||
483 | */ | ||
484 | uint64_t uid; | ||
485 | |||
486 | /** | ||
487 | * Source of the request. Replies should be forwarded to | ||
488 | * this peer. | ||
489 | */ | ||
490 | struct GNUNET_PeerIdentity source; | ||
491 | |||
492 | /** | ||
493 | * If this was a local request, remember the client; otherwise NULL. | ||
494 | */ | ||
495 | struct ClientList *client; | ||
496 | |||
497 | /** | ||
498 | * Pointer to this nodes heap location (for removal) | ||
499 | */ | ||
500 | struct GNUNET_CONTAINER_HeapNode *hnode; | ||
501 | |||
502 | /** | ||
503 | * Back pointer to the record storing this information. | ||
504 | */ | ||
505 | struct DHTQueryRecord *record; | ||
506 | |||
507 | /** | ||
508 | * Task to remove this entry on timeout. | ||
509 | */ | ||
510 | GNUNET_SCHEDULER_TaskIdentifier delete_task; | ||
511 | |||
512 | /** | ||
513 | * Bloomfilter of peers we have already sent back as | ||
514 | * replies to the initial request. Allows us to not | ||
515 | * forward the same peer multiple times for a find peer | ||
516 | * request. | ||
517 | */ | ||
518 | struct GNUNET_CONTAINER_BloomFilter *find_peers_responded; | ||
519 | |||
520 | }; | ||
521 | |||
522 | |||
523 | /** | ||
524 | * Entry in the DHT routing table. | ||
525 | */ | ||
526 | struct DHTQueryRecord | ||
527 | { | ||
528 | /** | ||
529 | * Head of DLL for result forwarding. | ||
530 | */ | ||
531 | struct DHTRouteSource *head; | ||
532 | |||
533 | /** | ||
534 | * Tail of DLL for result forwarding. | ||
535 | */ | ||
536 | struct DHTRouteSource *tail; | ||
537 | |||
538 | /** | ||
539 | * Key that the record concerns. | ||
540 | */ | ||
541 | GNUNET_HashCode key; | ||
542 | |||
543 | }; | ||
544 | |||
545 | |||
546 | /** | ||
547 | * Context used to calculate the number of find peer messages | ||
548 | * per X time units since our last scheduled find peer message | ||
549 | * was sent. If we have seen too many messages, delay or don't | ||
550 | * send our own out. | ||
551 | */ | ||
552 | struct FindPeerMessageContext | ||
553 | { | ||
554 | unsigned int count; | ||
555 | |||
556 | struct GNUNET_TIME_Absolute start; | ||
557 | |||
558 | struct GNUNET_TIME_Absolute end; | ||
559 | }; | ||
560 | |||
561 | |||
562 | /** | ||
563 | * DHT Routing results structure | ||
564 | */ | ||
565 | struct DHTResults | ||
566 | { | ||
567 | /** | ||
568 | * Min heap for removal upon reaching limit | ||
569 | */ | ||
570 | struct GNUNET_CONTAINER_Heap *minHeap; | ||
571 | |||
572 | |||
573 | /** | ||
574 | * Hashmap for fast key based lookup | ||
575 | */ | ||
576 | struct GNUNET_CONTAINER_MultiHashMap *hashmap; | ||
577 | }; | ||
578 | |||
579 | |||
580 | /** | ||
581 | * DHT structure for recent requests. | ||
582 | */ | ||
583 | struct RecentRequests | ||
584 | { | ||
585 | /** | ||
586 | * Min heap for removal upon reaching limit | ||
587 | */ | ||
588 | struct GNUNET_CONTAINER_Heap *minHeap; | ||
589 | |||
590 | #if HAVE_UID_FOR_TESTING > 1 | ||
591 | /** | ||
592 | * Hashmap for key based lookup | ||
593 | */ | ||
594 | struct GNUNET_CONTAINER_MultiHashMap *hashmap; | ||
595 | #endif | ||
596 | |||
597 | }; | ||
598 | |||
599 | |||
600 | struct RecentRequest | ||
601 | { | ||
602 | /** | ||
603 | * Position of this node in the min heap. | ||
604 | */ | ||
605 | struct GNUNET_CONTAINER_HeapNode *heap_node; | ||
606 | |||
607 | /** | ||
608 | * Bloomfilter containing entries for peers | ||
609 | * we forwarded this request to. | ||
610 | */ | ||
611 | struct GNUNET_CONTAINER_BloomFilter *bloom; | ||
612 | |||
613 | /** | ||
614 | * Timestamp of this request, for ordering | ||
615 | * the min heap. | ||
616 | */ | ||
617 | struct GNUNET_TIME_Absolute timestamp; | ||
618 | |||
619 | /** | ||
620 | * Key of this request. | ||
621 | */ | ||
622 | GNUNET_HashCode key; | ||
623 | |||
624 | /** | ||
625 | * Unique identifier for this request, 0 if from another peer. | ||
626 | */ | ||
627 | uint64_t uid; | ||
628 | |||
629 | /** | ||
630 | * Task to remove this entry on timeout. | ||
631 | */ | ||
632 | GNUNET_SCHEDULER_TaskIdentifier remove_task; | ||
633 | }; | ||
634 | |||
635 | |||
636 | /** | ||
637 | * log of the current network size estimate, used as the point where | ||
638 | * we switch between random and deterministic routing. Default | ||
639 | * value of 4.0 is used if NSE module is not available (i.e. not | ||
640 | * configured). | ||
641 | */ | ||
642 | static double log_of_network_size_estimate = 4.0; | ||
643 | |||
644 | /** | ||
645 | * Recent requests by hash/uid and by time inserted. | ||
646 | */ | ||
647 | static struct RecentRequests recent; | ||
648 | |||
649 | /** | ||
650 | * Context to use to calculate find peer rates. | ||
651 | */ | ||
652 | static struct FindPeerMessageContext find_peer_context; | ||
653 | |||
654 | /** | ||
655 | * Don't use our routing algorithm, always route | ||
656 | * to closest peer; initially send requests to 3 | ||
657 | * peers. | ||
658 | */ | ||
659 | static int strict_kademlia; | ||
660 | |||
661 | /** | ||
662 | * Routing option to end routing when closest peer found. | ||
663 | */ | ||
664 | static int stop_on_closest; | ||
665 | |||
666 | /** | ||
667 | * Routing option to end routing when data is found. | ||
668 | */ | ||
669 | static int stop_on_found; | ||
670 | |||
671 | /** | ||
672 | * Whether DHT needs to manage find peer requests, or | ||
673 | * an external force will do it on behalf of the DHT. | ||
674 | */ | ||
675 | static int do_find_peer; | ||
676 | |||
677 | /** | ||
678 | * Use exactly the forwarding formula as described in | ||
679 | * the paper if set to GNUNET_YES, otherwise use the | ||
680 | * slightly modified version. | ||
681 | */ | ||
682 | static int paper_forwarding; | ||
683 | |||
684 | /** | ||
685 | * PUT Peer Identities of peers we know about into | ||
686 | * the datacache. | ||
687 | */ | ||
688 | static int put_peer_identities; | ||
689 | |||
690 | /** | ||
691 | * Use the "real" distance metric when selecting the | ||
692 | * next routing hop. Can be less accurate. | ||
693 | */ | ||
694 | static int use_real_distance; | ||
695 | |||
696 | /** | ||
697 | * How many peers have we added since we sent out our last | ||
698 | * find peer request? | ||
699 | */ | ||
700 | static unsigned int newly_found_peers; | ||
701 | |||
702 | /** | ||
703 | * Container of active queries we should remember | ||
704 | */ | ||
705 | static struct DHTResults forward_list; | ||
706 | |||
707 | /** | ||
708 | * Handle to the datacache service (for inserting/retrieving data) | ||
709 | */ | ||
710 | static struct GNUNET_DATACACHE_Handle *datacache; | ||
711 | |||
712 | /** | ||
713 | * Handle for the statistics service. | ||
714 | */ | ||
715 | struct GNUNET_STATISTICS_Handle *stats; | ||
716 | |||
717 | /** | ||
718 | * Handle to get our current HELLO. | ||
719 | */ | ||
720 | static struct GNUNET_TRANSPORT_GetHelloHandle *ghh; | ||
721 | |||
722 | /** | ||
723 | * The configuration the DHT service is running with | ||
724 | */ | ||
725 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
726 | |||
727 | /** | ||
728 | * Handle to the core service | ||
729 | */ | ||
730 | static struct GNUNET_CORE_Handle *coreAPI; | ||
731 | |||
732 | /** | ||
733 | * Handle to the transport service, for getting our hello | ||
734 | */ | ||
735 | static struct GNUNET_TRANSPORT_Handle *transport_handle; | ||
736 | |||
737 | /** | ||
738 | * The identity of our peer. | ||
739 | */ | ||
740 | static struct GNUNET_PeerIdentity my_identity; | ||
741 | |||
742 | /** | ||
743 | * Short id of the peer, for printing | ||
744 | */ | ||
745 | static char *my_short_id; | ||
746 | |||
747 | /** | ||
748 | * Our HELLO | ||
749 | */ | ||
750 | static struct GNUNET_MessageHeader *my_hello; | ||
751 | |||
752 | /** | ||
753 | * Task to run when we shut down, cleaning up all our trash | ||
754 | */ | ||
755 | static GNUNET_SCHEDULER_TaskIdentifier cleanup_task; | ||
756 | |||
757 | /** | ||
758 | * The lowest currently used bucket. | ||
759 | */ | ||
760 | static unsigned int lowest_bucket; /* Initially equal to MAX_BUCKETS - 1 */ | ||
761 | |||
762 | /** | ||
763 | * The buckets (Kademlia routing table, complete with growth). | ||
764 | * Array of size MAX_BUCKET_SIZE. | ||
765 | */ | ||
766 | static struct PeerBucket k_buckets[MAX_BUCKETS]; | ||
767 | |||
768 | /** | ||
769 | * Hash map of all known peers, for easy removal from k_buckets on disconnect. | ||
770 | */ | ||
771 | static struct GNUNET_CONTAINER_MultiHashMap *all_known_peers; | ||
772 | |||
773 | /** | ||
774 | * Recently seen find peer requests. | ||
775 | */ | ||
776 | static struct GNUNET_CONTAINER_MultiHashMap *recent_find_peer_requests; | ||
777 | |||
778 | /** | ||
779 | * Maximum size for each bucket. | ||
780 | */ | ||
781 | static unsigned int bucket_size = DEFAULT_BUCKET_SIZE; | ||
782 | |||
783 | /** | ||
784 | * List of active clients. | ||
785 | */ | ||
786 | static struct ClientList *client_list; | ||
787 | |||
788 | /** | ||
789 | * Handle to the DHT logger. | ||
790 | */ | ||
791 | static struct GNUNET_DHTLOG_Handle *dhtlog_handle; | ||
792 | |||
793 | /** | ||
794 | * Whether or not to send routing debugging information | ||
795 | * to the dht logging server | ||
796 | */ | ||
797 | static unsigned int debug_routes; | ||
798 | |||
799 | /** | ||
800 | * Whether or not to send FULL route information to | ||
801 | * logging server | ||
802 | */ | ||
803 | static unsigned int debug_routes_extended; | ||
804 | |||
805 | /** | ||
806 | * GNUNET_YES or GNUNET_NO, whether or not to act as | ||
807 | * a malicious node which drops all messages | ||
808 | */ | ||
809 | static unsigned int malicious_dropper; | ||
810 | |||
811 | /** | ||
812 | * GNUNET_YES or GNUNET_NO, whether or not to act as | ||
813 | * a malicious node which sends out lots of GETS | ||
814 | */ | ||
815 | static unsigned int malicious_getter; | ||
816 | |||
817 | /** | ||
818 | * GNUNET_YES or GNUNET_NO, whether or not to act as | ||
819 | * a malicious node which sends out lots of PUTS | ||
820 | */ | ||
821 | static unsigned int malicious_putter; | ||
822 | |||
823 | /** | ||
824 | * Frequency for malicious get requests. | ||
825 | */ | ||
826 | static struct GNUNET_TIME_Relative malicious_get_frequency; | ||
827 | |||
828 | /** | ||
829 | * Frequency for malicious put requests. | ||
830 | */ | ||
831 | static struct GNUNET_TIME_Relative malicious_put_frequency; | ||
832 | |||
833 | /** | ||
834 | * Kademlia replication | ||
835 | */ | ||
836 | static unsigned long long kademlia_replication; | ||
837 | |||
838 | /** | ||
839 | * Reply times for requests, if we are busy, don't send any | ||
840 | * more requests! | ||
841 | */ | ||
842 | static struct GNUNET_TIME_Relative reply_times[MAX_REPLY_TIMES]; | ||
843 | |||
844 | /** | ||
845 | * Current counter for replies. | ||
846 | */ | ||
847 | static unsigned int reply_counter; | ||
848 | |||
849 | /** | ||
850 | * Our handle to the BLOCK library. | ||
851 | */ | ||
852 | static struct GNUNET_BLOCK_Context *block_context; | ||
853 | |||
854 | /** | ||
855 | * Network size estimation handle. | ||
856 | */ | ||
857 | static struct GNUNET_NSE_Handle *nse; | ||
858 | |||
859 | |||
860 | /** | ||
861 | * Callback that is called when network size estimate is updated. | ||
862 | * | ||
863 | * @param cls closure | ||
864 | * @param timestamp time when the estimate was received from the server (or created by the server) | ||
865 | * @param logestimate the log(Base 2) value of the current network size estimate | ||
866 | * @param std_dev standard deviation for the estimate | ||
867 | * | ||
868 | */ | ||
869 | static void | ||
870 | update_network_size_estimate (void *cls, struct GNUNET_TIME_Absolute timestamp, | ||
871 | double logestimate, double std_dev) | ||
872 | { | ||
873 | log_of_network_size_estimate = logestimate; | ||
874 | } | ||
875 | |||
876 | |||
877 | /** | ||
878 | * Forward declaration. | ||
879 | */ | ||
880 | static size_t | ||
881 | send_generic_reply (void *cls, size_t size, void *buf); | ||
882 | |||
883 | |||
884 | /** Declare here so retry_core_send is aware of it */ | ||
885 | static size_t | ||
886 | core_transmit_notify (void *cls, size_t size, void *buf); | ||
887 | |||
888 | |||
889 | /** | ||
890 | * Convert unique ID to hash code. | ||
891 | * | ||
892 | * @param uid unique ID to convert | ||
893 | * @param hash set to uid (extended with zeros) | ||
894 | */ | ||
895 | static void | ||
896 | hash_from_uid (uint64_t uid, GNUNET_HashCode * hash) | ||
897 | { | ||
898 | memset (hash, 0, sizeof (GNUNET_HashCode)); | ||
899 | *((uint64_t *) hash) = uid; | ||
900 | } | ||
901 | |||
902 | |||
903 | /** | ||
904 | * Given the largest send delay, artificially decrease it | ||
905 | * so the next time around we may have a chance at sending | ||
906 | * again. | ||
907 | */ | ||
908 | static void | ||
909 | decrease_max_send_delay (struct GNUNET_TIME_Relative max_time) | ||
910 | { | ||
911 | unsigned int i; | ||
912 | |||
913 | for (i = 0; i < MAX_REPLY_TIMES; i++) | ||
914 | { | ||
915 | if (reply_times[i].rel_value == max_time.rel_value) | ||
916 | { | ||
917 | reply_times[i].rel_value = reply_times[i].rel_value / 2; | ||
918 | return; | ||
919 | } | ||
920 | } | ||
921 | } | ||
922 | |||
923 | |||
924 | /** | ||
925 | * Find the maximum send time of the recently sent values. | ||
926 | * | ||
927 | * @return the average time between asking core to send a message | ||
928 | * and when the buffer for copying it is passed | ||
929 | */ | ||
930 | static struct GNUNET_TIME_Relative | ||
931 | get_max_send_delay () | ||
932 | { | ||
933 | unsigned int i; | ||
934 | struct GNUNET_TIME_Relative max_time; | ||
935 | |||
936 | max_time = GNUNET_TIME_relative_get_zero (); | ||
937 | |||
938 | for (i = 0; i < MAX_REPLY_TIMES; i++) | ||
939 | { | ||
940 | if (reply_times[i].rel_value > max_time.rel_value) | ||
941 | max_time.rel_value = reply_times[i].rel_value; | ||
942 | } | ||
943 | #if DEBUG_DHT | ||
944 | if (max_time.rel_value > MAX_REQUEST_TIME.rel_value) | ||
945 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Max send delay was %llu\n", | ||
946 | (unsigned long long) max_time.rel_value); | ||
947 | #endif | ||
948 | return max_time; | ||
949 | } | ||
950 | |||
951 | |||
952 | static void | ||
953 | increment_stats (const char *value) | ||
954 | { | ||
955 | if (stats == NULL) | ||
956 | return; | ||
957 | GNUNET_STATISTICS_update (stats, value, 1, GNUNET_NO); | ||
958 | } | ||
959 | |||
960 | |||
961 | static void | ||
962 | decrement_stats (const char *value) | ||
963 | { | ||
964 | if (stats == NULL) | ||
965 | return; | ||
966 | GNUNET_STATISTICS_update (stats, value, -1, GNUNET_NO); | ||
967 | } | ||
968 | |||
969 | |||
970 | /** | ||
971 | * Try to send another message from our core send list | ||
972 | */ | ||
973 | static void | ||
974 | try_core_send (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
975 | { | ||
976 | struct PeerInfo *peer = cls; | ||
977 | struct P2PPendingMessage *pending; | ||
978 | size_t ssize; | ||
979 | |||
980 | peer->send_task = GNUNET_SCHEDULER_NO_TASK; | ||
981 | |||
982 | if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) | ||
983 | return; | ||
984 | |||
985 | if (peer->th != NULL) | ||
986 | return; /* Message send already in progress */ | ||
987 | |||
988 | pending = peer->head; | ||
989 | if (pending != NULL) | ||
990 | { | ||
991 | ssize = ntohs (pending->msg->size); | ||
992 | #if DEBUG_DHT > 1 | ||
993 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
994 | "`%s:%s': Calling notify_transmit_ready with size %d for peer %s\n", | ||
995 | my_short_id, "DHT", ssize, GNUNET_i2s (&peer->id)); | ||
996 | #endif | ||
997 | pending->scheduled = GNUNET_TIME_absolute_get (); | ||
998 | reply_counter++; | ||
999 | if (reply_counter >= MAX_REPLY_TIMES) | ||
1000 | reply_counter = 0; | ||
1001 | peer->th = | ||
1002 | GNUNET_CORE_notify_transmit_ready (coreAPI, GNUNET_YES, | ||
1003 | pending->importance, | ||
1004 | pending->timeout, &peer->id, ssize, | ||
1005 | &core_transmit_notify, peer); | ||
1006 | if (peer->th == NULL) | ||
1007 | increment_stats ("# notify transmit ready failed"); | ||
1008 | } | ||
1009 | } | ||
1010 | |||
1011 | |||
1012 | /** | ||
1013 | * Function called to send a request out to another peer. | ||
1014 | * Called both for locally initiated requests and those | ||
1015 | * received from other peers. | ||
1016 | * | ||
1017 | * @param msg the encapsulated message | ||
1018 | * @param peer the peer to forward the message to | ||
1019 | * @param msg_ctx the context of the message (hop count, bloom, etc.) | ||
1020 | */ | ||
1021 | static void | ||
1022 | forward_result_message (const struct GNUNET_MessageHeader *msg, | ||
1023 | struct PeerInfo *peer, | ||
1024 | struct DHT_MessageContext *msg_ctx) | ||
1025 | { | ||
1026 | struct GNUNET_DHT_P2PRouteResultMessage *result_message; | ||
1027 | struct P2PPendingMessage *pending; | ||
1028 | size_t msize; | ||
1029 | size_t psize; | ||
1030 | char *path_start; | ||
1031 | char *path_offset; | ||
1032 | |||
1033 | #if DEBUG_PATH | ||
1034 | unsigned int i; | ||
1035 | #endif | ||
1036 | |||
1037 | increment_stats (STAT_RESULT_FORWARDS); | ||
1038 | msize = | ||
1039 | sizeof (struct GNUNET_DHT_P2PRouteResultMessage) + ntohs (msg->size) + | ||
1040 | (sizeof (struct GNUNET_PeerIdentity) * msg_ctx->path_history_len); | ||
1041 | GNUNET_assert (msize <= GNUNET_SERVER_MAX_MESSAGE_SIZE); | ||
1042 | psize = sizeof (struct P2PPendingMessage) + msize; | ||
1043 | pending = GNUNET_malloc (psize); | ||
1044 | pending->msg = (struct GNUNET_MessageHeader *) &pending[1]; | ||
1045 | pending->importance = DHT_SEND_PRIORITY; | ||
1046 | pending->timeout = GNUNET_TIME_relative_get_forever (); | ||
1047 | result_message = (struct GNUNET_DHT_P2PRouteResultMessage *) pending->msg; | ||
1048 | result_message->header.size = htons (msize); | ||
1049 | result_message->header.type = | ||
1050 | htons (GNUNET_MESSAGE_TYPE_DHT_P2P_ROUTE_RESULT); | ||
1051 | result_message->outgoing_path_length = htonl (msg_ctx->path_history_len); | ||
1052 | if (msg_ctx->path_history_len > 0) | ||
1053 | { | ||
1054 | /* End of pending is where enc_msg starts */ | ||
1055 | path_start = (char *) &pending[1]; | ||
1056 | /* Offset by the size of the enc_msg */ | ||
1057 | path_start += ntohs (msg->size); | ||
1058 | memcpy (path_start, msg_ctx->path_history, | ||
1059 | msg_ctx->path_history_len * (sizeof (struct GNUNET_PeerIdentity))); | ||
1060 | #if DEBUG_PATH | ||
1061 | for (i = 0; i < msg_ctx->path_history_len; i++) | ||
1062 | { | ||
1063 | path_offset = | ||
1064 | &msg_ctx->path_history[i * sizeof (struct GNUNET_PeerIdentity)]; | ||
1065 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1066 | "(forward_result) Key %s Found peer %d:%s\n", | ||
1067 | GNUNET_h2s (&msg_ctx->key), i, | ||
1068 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) path_offset)); | ||
1069 | } | ||
1070 | #endif | ||
1071 | } | ||
1072 | result_message->options = htonl (msg_ctx->msg_options); | ||
1073 | result_message->hop_count = htonl (msg_ctx->hop_count + 1); | ||
1074 | #if HAVE_UID_FOR_TESTING | ||
1075 | result_message->unique_id = GNUNET_htonll (msg_ctx->unique_id); | ||
1076 | #endif | ||
1077 | memcpy (&result_message->key, &msg_ctx->key, sizeof (GNUNET_HashCode)); | ||
1078 | /* Copy the enc_msg, then the path history as well! */ | ||
1079 | memcpy (&result_message[1], msg, ntohs (msg->size)); | ||
1080 | path_offset = (char *) &result_message[1]; | ||
1081 | path_offset += ntohs (msg->size); | ||
1082 | /* If we have path history, copy it to the end of the whole thing */ | ||
1083 | if (msg_ctx->path_history_len > 0) | ||
1084 | memcpy (path_offset, msg_ctx->path_history, | ||
1085 | msg_ctx->path_history_len * (sizeof (struct GNUNET_PeerIdentity))); | ||
1086 | #if DEBUG_DHT > 1 | ||
1087 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1088 | "%s:%s Adding pending message size %d for peer %s\n", my_short_id, | ||
1089 | "DHT", msize, GNUNET_i2s (&peer->id)); | ||
1090 | #endif | ||
1091 | peer->pending_count++; | ||
1092 | increment_stats ("# pending messages scheduled"); | ||
1093 | GNUNET_CONTAINER_DLL_insert_after (peer->head, peer->tail, peer->tail, | ||
1094 | pending); | ||
1095 | if (peer->send_task == GNUNET_SCHEDULER_NO_TASK) | ||
1096 | peer->send_task = GNUNET_SCHEDULER_add_now (&try_core_send, peer); | ||
1097 | } | ||
1098 | |||
1099 | |||
1100 | /** | ||
1101 | * Called when core is ready to send a message we asked for | ||
1102 | * out to the destination. | ||
1103 | * | ||
1104 | * @param cls closure (NULL) | ||
1105 | * @param size number of bytes available in buf | ||
1106 | * @param buf where the callee should write the message | ||
1107 | * @return number of bytes written to buf | ||
1108 | */ | ||
1109 | static size_t | ||
1110 | core_transmit_notify (void *cls, size_t size, void *buf) | ||
1111 | { | ||
1112 | struct PeerInfo *peer = cls; | ||
1113 | char *cbuf = buf; | ||
1114 | struct P2PPendingMessage *pending; | ||
1115 | |||
1116 | size_t off; | ||
1117 | size_t msize; | ||
1118 | |||
1119 | peer->th = NULL; | ||
1120 | if (buf == NULL) | ||
1121 | { | ||
1122 | /* client disconnected */ | ||
1123 | #if DEBUG_DHT | ||
1124 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s:%s': buffer was NULL\n", | ||
1125 | my_short_id, "DHT"); | ||
1126 | #endif | ||
1127 | return 0; | ||
1128 | } | ||
1129 | |||
1130 | if (peer->head == NULL) | ||
1131 | return 0; | ||
1132 | |||
1133 | off = 0; | ||
1134 | pending = peer->head; | ||
1135 | #if DUMB | ||
1136 | reply_times[reply_counter] = | ||
1137 | GNUNET_TIME_absolute_get_difference (pending->scheduled, | ||
1138 | GNUNET_TIME_absolute_get ()); | ||
1139 | msize = ntohs (pending->msg->size); | ||
1140 | if (msize <= size) | ||
1141 | { | ||
1142 | off = msize; | ||
1143 | memcpy (cbuf, pending->msg, msize); | ||
1144 | peer->pending_count--; | ||
1145 | increment_stats ("# pending messages sent"); | ||
1146 | GNUNET_assert (peer->pending_count >= 0); | ||
1147 | GNUNET_CONTAINER_DLL_remove (peer->head, peer->tail, pending); | ||
1148 | GNUNET_free (pending); | ||
1149 | } | ||
1150 | #else | ||
1151 | while (NULL != pending && | ||
1152 | (size - off >= (msize = ntohs (pending->msg->size)))) | ||
1153 | { | ||
1154 | memcpy (&cbuf[off], pending->msg, msize); | ||
1155 | off += msize; | ||
1156 | peer->pending_count--; | ||
1157 | increment_stats ("# pending messages sent"); | ||
1158 | GNUNET_CONTAINER_DLL_remove (peer->head, peer->tail, pending); | ||
1159 | GNUNET_free (pending); | ||
1160 | pending = peer->head; | ||
1161 | } | ||
1162 | #endif | ||
1163 | if ((peer->head != NULL) && (peer->send_task == GNUNET_SCHEDULER_NO_TASK)) | ||
1164 | peer->send_task = GNUNET_SCHEDULER_add_now (&try_core_send, peer); | ||
1165 | |||
1166 | return off; | ||
1167 | } | ||
1168 | |||
1169 | |||
1170 | /** | ||
1171 | * Compute the distance between have and target as a 32-bit value. | ||
1172 | * Differences in the lower bits must count stronger than differences | ||
1173 | * in the higher bits. | ||
1174 | * | ||
1175 | * @return 0 if have==target, otherwise a number | ||
1176 | * that is larger as the distance between | ||
1177 | * the two hash codes increases | ||
1178 | */ | ||
1179 | static unsigned int | ||
1180 | distance (const GNUNET_HashCode * target, const GNUNET_HashCode * have) | ||
1181 | { | ||
1182 | unsigned int bucket; | ||
1183 | unsigned int msb; | ||
1184 | unsigned int lsb; | ||
1185 | unsigned int i; | ||
1186 | |||
1187 | /* We have to represent the distance between two 2^9 (=512)-bit | ||
1188 | * numbers as a 2^5 (=32)-bit number with "0" being used for the | ||
1189 | * two numbers being identical; furthermore, we need to | ||
1190 | * guarantee that a difference in the number of matching | ||
1191 | * bits is always represented in the result. | ||
1192 | * | ||
1193 | * We use 2^32/2^9 numerical values to distinguish between | ||
1194 | * hash codes that have the same LSB bit distance and | ||
1195 | * use the highest 2^9 bits of the result to signify the | ||
1196 | * number of (mis)matching LSB bits; if we have 0 matching | ||
1197 | * and hence 512 mismatching LSB bits we return -1 (since | ||
1198 | * 512 itself cannot be represented with 9 bits) */ | ||
1199 | |||
1200 | /* first, calculate the most significant 9 bits of our | ||
1201 | * result, aka the number of LSBs */ | ||
1202 | bucket = GNUNET_CRYPTO_hash_matching_bits (target, have); | ||
1203 | /* bucket is now a value between 0 and 512 */ | ||
1204 | if (bucket == 512) | ||
1205 | return 0; /* perfect match */ | ||
1206 | if (bucket == 0) | ||
1207 | return (unsigned int) -1; /* LSB differs; use max (if we did the bit-shifting | ||
1208 | * below, we'd end up with max+1 (overflow)) */ | ||
1209 | |||
1210 | /* calculate the most significant bits of the final result */ | ||
1211 | msb = (512 - bucket) << (32 - 9); | ||
1212 | /* calculate the 32-9 least significant bits of the final result by | ||
1213 | * looking at the differences in the 32-9 bits following the | ||
1214 | * mismatching bit at 'bucket' */ | ||
1215 | lsb = 0; | ||
1216 | for (i = bucket + 1; | ||
1217 | (i < sizeof (GNUNET_HashCode) * 8) && (i < bucket + 1 + 32 - 9); i++) | ||
1218 | { | ||
1219 | if (GNUNET_CRYPTO_hash_get_bit (target, i) != | ||
1220 | GNUNET_CRYPTO_hash_get_bit (have, i)) | ||
1221 | lsb |= (1 << (bucket + 32 - 9 - i)); /* first bit set will be 10, | ||
1222 | * last bit set will be 31 -- if | ||
1223 | * i does not reach 512 first... */ | ||
1224 | } | ||
1225 | return msb | lsb; | ||
1226 | } | ||
1227 | |||
1228 | |||
1229 | /** | ||
1230 | * Return a number that is larger the closer the | ||
1231 | * "have" GNUNET_hash code is to the "target". | ||
1232 | * | ||
1233 | * @return inverse distance metric, non-zero. | ||
1234 | * Must fudge the value if NO bits match. | ||
1235 | */ | ||
1236 | static unsigned int | ||
1237 | inverse_distance (const GNUNET_HashCode * target, const GNUNET_HashCode * have) | ||
1238 | { | ||
1239 | if (GNUNET_CRYPTO_hash_matching_bits (target, have) == 0) | ||
1240 | return 1; /* Never return 0! */ | ||
1241 | return ((unsigned int) -1) - distance (target, have); | ||
1242 | } | ||
1243 | |||
1244 | |||
1245 | /** | ||
1246 | * Find the optimal bucket for this key, regardless | ||
1247 | * of the current number of buckets in use. | ||
1248 | * | ||
1249 | * @param hc the hashcode to compare our identity to | ||
1250 | * | ||
1251 | * @return the proper bucket index, or GNUNET_SYSERR | ||
1252 | * on error (same hashcode) | ||
1253 | */ | ||
1254 | static int | ||
1255 | find_bucket (const GNUNET_HashCode * hc) | ||
1256 | { | ||
1257 | unsigned int bits; | ||
1258 | |||
1259 | bits = GNUNET_CRYPTO_hash_matching_bits (&my_identity.hashPubKey, hc); | ||
1260 | if (bits == MAX_BUCKETS) | ||
1261 | return GNUNET_SYSERR; | ||
1262 | return MAX_BUCKETS - bits - 1; | ||
1263 | } | ||
1264 | |||
1265 | |||
1266 | /** | ||
1267 | * Find which k-bucket this peer should go into, | ||
1268 | * taking into account the size of the k-bucket | ||
1269 | * array. This means that if more bits match than | ||
1270 | * there are currently buckets, lowest_bucket will | ||
1271 | * be returned. | ||
1272 | * | ||
1273 | * @param hc GNUNET_HashCode we are finding the bucket for. | ||
1274 | * | ||
1275 | * @return the proper bucket index for this key, | ||
1276 | * or GNUNET_SYSERR on error (same hashcode) | ||
1277 | */ | ||
1278 | static int | ||
1279 | find_current_bucket (const GNUNET_HashCode * hc) | ||
1280 | { | ||
1281 | int actual_bucket; | ||
1282 | |||
1283 | actual_bucket = find_bucket (hc); | ||
1284 | if (actual_bucket == GNUNET_SYSERR) /* hc and our peer identity match! */ | ||
1285 | return lowest_bucket; | ||
1286 | if (actual_bucket < lowest_bucket) /* actual_bucket not yet used */ | ||
1287 | return lowest_bucket; | ||
1288 | return actual_bucket; | ||
1289 | } | ||
1290 | |||
1291 | |||
1292 | /** | ||
1293 | * Find a routing table entry from a peer identity | ||
1294 | * | ||
1295 | * @param peer the peer identity to look up | ||
1296 | * | ||
1297 | * @return the routing table entry, or NULL if not found | ||
1298 | */ | ||
1299 | static struct PeerInfo * | ||
1300 | find_peer_by_id (const struct GNUNET_PeerIdentity *peer) | ||
1301 | { | ||
1302 | int bucket; | ||
1303 | struct PeerInfo *pos; | ||
1304 | |||
1305 | bucket = find_current_bucket (&peer->hashPubKey); | ||
1306 | |||
1307 | if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity))) | ||
1308 | return NULL; | ||
1309 | |||
1310 | pos = k_buckets[bucket].head; | ||
1311 | while (pos != NULL) | ||
1312 | { | ||
1313 | if (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity))) | ||
1314 | return pos; | ||
1315 | pos = pos->next; | ||
1316 | } | ||
1317 | return NULL; /* No such peer. */ | ||
1318 | } | ||
1319 | |||
1320 | /* Forward declaration */ | ||
1321 | static void | ||
1322 | update_core_preference (void *cls, | ||
1323 | const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
1324 | |||
1325 | |||
1326 | /** | ||
1327 | * Function called with statistics about the given peer. | ||
1328 | * | ||
1329 | * @param cls closure | ||
1330 | * @param peer identifies the peer | ||
1331 | * @param bpm_out set to the current bandwidth limit (sending) for this peer | ||
1332 | * @param amount set to the amount that was actually reserved or unreserved; | ||
1333 | * either the full requested amount or zero (no partial reservations) | ||
1334 | * @param res_delay if the reservation could not be satisfied (amount was 0), how | ||
1335 | * long should the client wait until re-trying? | ||
1336 | * @param preference current traffic preference for the given peer | ||
1337 | */ | ||
1338 | static void | ||
1339 | update_core_preference_finish (void *cls, | ||
1340 | const struct GNUNET_PeerIdentity *peer, | ||
1341 | struct GNUNET_BANDWIDTH_Value32NBO bpm_out, | ||
1342 | int32_t amount, | ||
1343 | struct GNUNET_TIME_Relative res_delay, | ||
1344 | uint64_t preference) | ||
1345 | { | ||
1346 | struct PeerInfo *peer_info = cls; | ||
1347 | |||
1348 | peer_info->info_ctx = NULL; | ||
1349 | GNUNET_SCHEDULER_add_delayed (DHT_DEFAULT_PREFERENCE_INTERVAL, | ||
1350 | &update_core_preference, peer_info); | ||
1351 | } | ||
1352 | |||
1353 | static void | ||
1354 | update_core_preference (void *cls, | ||
1355 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1356 | { | ||
1357 | struct PeerInfo *peer = cls; | ||
1358 | uint64_t preference; | ||
1359 | unsigned int matching; | ||
1360 | |||
1361 | if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) | ||
1362 | { | ||
1363 | return; | ||
1364 | } | ||
1365 | matching = | ||
1366 | GNUNET_CRYPTO_hash_matching_bits (&my_identity.hashPubKey, | ||
1367 | &peer->id.hashPubKey); | ||
1368 | if (matching >= 64) | ||
1369 | { | ||
1370 | #if DEBUG_DHT | ||
1371 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1372 | "Peer identifier matches by %u bits, only shifting as much as we can!\n", | ||
1373 | matching); | ||
1374 | #endif | ||
1375 | matching = 63; | ||
1376 | } | ||
1377 | preference = 1LL << matching; | ||
1378 | peer->info_ctx = | ||
1379 | GNUNET_CORE_peer_change_preference (coreAPI, &peer->id, | ||
1380 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
1381 | GNUNET_BANDWIDTH_VALUE_MAX, 0, | ||
1382 | preference, | ||
1383 | &update_core_preference_finish, peer); | ||
1384 | } | ||
1385 | |||
1386 | |||
1387 | /** | ||
1388 | * Given a peer and its corresponding bucket, | ||
1389 | * remove it from that bucket. Does not free | ||
1390 | * the PeerInfo struct, nor cancel messages | ||
1391 | * or free messages waiting to be sent to this | ||
1392 | * peer! | ||
1393 | * | ||
1394 | * @param peer the peer to remove | ||
1395 | * @param bucket the bucket the peer belongs to | ||
1396 | */ | ||
1397 | static void | ||
1398 | remove_peer (struct PeerInfo *peer, unsigned int bucket) | ||
1399 | { | ||
1400 | GNUNET_assert (k_buckets[bucket].peers_size > 0); | ||
1401 | GNUNET_CONTAINER_DLL_remove (k_buckets[bucket].head, k_buckets[bucket].tail, | ||
1402 | peer); | ||
1403 | k_buckets[bucket].peers_size--; | ||
1404 | #if CHANGE_LOWEST | ||
1405 | if ((bucket == lowest_bucket) && (k_buckets[lowest_bucket].peers_size == 0) && | ||
1406 | (lowest_bucket < MAX_BUCKETS - 1)) | ||
1407 | lowest_bucket++; | ||
1408 | #endif | ||
1409 | } | ||
1410 | |||
1411 | /** | ||
1412 | * Removes peer from a bucket, then frees associated | ||
1413 | * resources and frees peer. | ||
1414 | * | ||
1415 | * @param peer peer to be removed and freed | ||
1416 | * @param bucket which bucket this peer belongs to | ||
1417 | */ | ||
1418 | static void | ||
1419 | delete_peer (struct PeerInfo *peer, unsigned int bucket) | ||
1420 | { | ||
1421 | struct P2PPendingMessage *pos; | ||
1422 | struct P2PPendingMessage *next; | ||
1423 | |||
1424 | remove_peer (peer, bucket); /* First remove the peer from its bucket */ | ||
1425 | if (peer->send_task != GNUNET_SCHEDULER_NO_TASK) | ||
1426 | GNUNET_SCHEDULER_cancel (peer->send_task); | ||
1427 | if ((peer->th != NULL) && (coreAPI != NULL)) | ||
1428 | GNUNET_CORE_notify_transmit_ready_cancel (peer->th); | ||
1429 | |||
1430 | pos = peer->head; | ||
1431 | while (pos != NULL) /* Remove any pending messages for this peer */ | ||
1432 | { | ||
1433 | increment_stats | ||
1434 | ("# dht pending messages discarded (due to disconnect/shutdown)"); | ||
1435 | next = pos->next; | ||
1436 | GNUNET_free (pos); | ||
1437 | pos = next; | ||
1438 | } | ||
1439 | |||
1440 | GNUNET_assert (GNUNET_CONTAINER_multihashmap_contains | ||
1441 | (all_known_peers, &peer->id.hashPubKey)); | ||
1442 | GNUNET_assert (GNUNET_YES == | ||
1443 | GNUNET_CONTAINER_multihashmap_remove (all_known_peers, | ||
1444 | &peer->id.hashPubKey, | ||
1445 | peer)); | ||
1446 | GNUNET_free (peer); | ||
1447 | decrement_stats (STAT_PEERS_KNOWN); | ||
1448 | } | ||
1449 | |||
1450 | |||
1451 | /** | ||
1452 | * Iterator over hash map entries. | ||
1453 | * | ||
1454 | * @param cls closure | ||
1455 | * @param key current key code | ||
1456 | * @param value PeerInfo of the peer to move to new lowest bucket | ||
1457 | * @return GNUNET_YES if we should continue to | ||
1458 | * iterate, | ||
1459 | * GNUNET_NO if not. | ||
1460 | */ | ||
1461 | static int | ||
1462 | move_lowest_bucket (void *cls, const GNUNET_HashCode * key, void *value) | ||
1463 | { | ||
1464 | struct PeerInfo *peer = value; | ||
1465 | int new_bucket; | ||
1466 | |||
1467 | GNUNET_assert (lowest_bucket > 0); | ||
1468 | new_bucket = lowest_bucket - 1; | ||
1469 | remove_peer (peer, lowest_bucket); | ||
1470 | GNUNET_CONTAINER_DLL_insert_after (k_buckets[new_bucket].head, | ||
1471 | k_buckets[new_bucket].tail, | ||
1472 | k_buckets[new_bucket].tail, peer); | ||
1473 | k_buckets[new_bucket].peers_size++; | ||
1474 | return GNUNET_YES; | ||
1475 | } | ||
1476 | |||
1477 | |||
1478 | /** | ||
1479 | * The current lowest bucket is full, so change the lowest | ||
1480 | * bucket to the next lower down, and move any appropriate | ||
1481 | * entries in the current lowest bucket to the new bucket. | ||
1482 | */ | ||
1483 | static void | ||
1484 | enable_next_bucket () | ||
1485 | { | ||
1486 | struct GNUNET_CONTAINER_MultiHashMap *to_remove; | ||
1487 | struct PeerInfo *pos; | ||
1488 | |||
1489 | GNUNET_assert (lowest_bucket > 0); | ||
1490 | to_remove = GNUNET_CONTAINER_multihashmap_create (bucket_size); | ||
1491 | pos = k_buckets[lowest_bucket].head; | ||
1492 | |||
1493 | /* Populate the array of peers which should be in the next lowest bucket */ | ||
1494 | while (pos != NULL) | ||
1495 | { | ||
1496 | if (find_bucket (&pos->id.hashPubKey) < lowest_bucket) | ||
1497 | GNUNET_CONTAINER_multihashmap_put (to_remove, &pos->id.hashPubKey, pos, | ||
1498 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | ||
1499 | pos = pos->next; | ||
1500 | } | ||
1501 | |||
1502 | /* Remove peers from lowest bucket, insert into next lowest bucket */ | ||
1503 | GNUNET_CONTAINER_multihashmap_iterate (to_remove, &move_lowest_bucket, NULL); | ||
1504 | GNUNET_CONTAINER_multihashmap_destroy (to_remove); | ||
1505 | lowest_bucket = lowest_bucket - 1; | ||
1506 | } | ||
1507 | |||
1508 | |||
1509 | /** | ||
1510 | * Find the closest peer in our routing table to the | ||
1511 | * given hashcode. | ||
1512 | * | ||
1513 | * @return The closest peer in our routing table to the | ||
1514 | * key, or NULL on error. | ||
1515 | */ | ||
1516 | static struct PeerInfo * | ||
1517 | find_closest_peer (const GNUNET_HashCode * hc) | ||
1518 | { | ||
1519 | struct PeerInfo *pos; | ||
1520 | struct PeerInfo *current_closest; | ||
1521 | unsigned int lowest_distance; | ||
1522 | unsigned int temp_distance; | ||
1523 | int bucket; | ||
1524 | int count; | ||
1525 | |||
1526 | lowest_distance = -1; | ||
1527 | |||
1528 | if (k_buckets[lowest_bucket].peers_size == 0) | ||
1529 | return NULL; | ||
1530 | |||
1531 | current_closest = NULL; | ||
1532 | for (bucket = lowest_bucket; bucket < MAX_BUCKETS; bucket++) | ||
1533 | { | ||
1534 | pos = k_buckets[bucket].head; | ||
1535 | count = 0; | ||
1536 | while ((pos != NULL) && (count < bucket_size)) | ||
1537 | { | ||
1538 | temp_distance = distance (&pos->id.hashPubKey, hc); | ||
1539 | if (temp_distance <= lowest_distance) | ||
1540 | { | ||
1541 | lowest_distance = temp_distance; | ||
1542 | current_closest = pos; | ||
1543 | } | ||
1544 | pos = pos->next; | ||
1545 | count++; | ||
1546 | } | ||
1547 | } | ||
1548 | GNUNET_assert (current_closest != NULL); | ||
1549 | return current_closest; | ||
1550 | } | ||
1551 | |||
1552 | |||
1553 | /** | ||
1554 | * Function called to send a request out to another peer. | ||
1555 | * Called both for locally initiated requests and those | ||
1556 | * received from other peers. | ||
1557 | * | ||
1558 | * @param msg the encapsulated message | ||
1559 | * @param peer the peer to forward the message to | ||
1560 | * @param msg_ctx the context of the message (hop count, bloom, etc.) | ||
1561 | */ | ||
1562 | static void | ||
1563 | forward_message (const struct GNUNET_MessageHeader *msg, struct PeerInfo *peer, | ||
1564 | struct DHT_MessageContext *msg_ctx) | ||
1565 | { | ||
1566 | struct GNUNET_DHT_P2PRouteMessage *route_message; | ||
1567 | struct P2PPendingMessage *pending; | ||
1568 | size_t msize; | ||
1569 | size_t psize; | ||
1570 | char *route_path; | ||
1571 | |||
1572 | increment_stats (STAT_ROUTE_FORWARDS); | ||
1573 | GNUNET_assert (peer != NULL); | ||
1574 | if ((msg_ctx->closest != GNUNET_YES) && | ||
1575 | (peer == find_closest_peer (&msg_ctx->key))) | ||
1576 | increment_stats (STAT_ROUTE_FORWARDS_CLOSEST); | ||
1577 | |||
1578 | msize = | ||
1579 | sizeof (struct GNUNET_DHT_P2PRouteMessage) + ntohs (msg->size) + | ||
1580 | (msg_ctx->path_history_len * sizeof (struct GNUNET_PeerIdentity)); | ||
1581 | GNUNET_assert (msize <= GNUNET_SERVER_MAX_MESSAGE_SIZE); | ||
1582 | psize = sizeof (struct P2PPendingMessage) + msize; | ||
1583 | pending = GNUNET_malloc (psize); | ||
1584 | pending->msg = (struct GNUNET_MessageHeader *) &pending[1]; | ||
1585 | pending->importance = msg_ctx->importance; | ||
1586 | pending->timeout = msg_ctx->timeout; | ||
1587 | route_message = (struct GNUNET_DHT_P2PRouteMessage *) pending->msg; | ||
1588 | route_message->header.size = htons (msize); | ||
1589 | route_message->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_P2P_ROUTE); | ||
1590 | route_message->options = htonl (msg_ctx->msg_options); | ||
1591 | route_message->hop_count = htonl (msg_ctx->hop_count + 1); | ||
1592 | route_message->network_size = htonl (msg_ctx->network_size); | ||
1593 | route_message->desired_replication_level = htonl (msg_ctx->replication); | ||
1594 | #if HAVE_UID_FOR_TESTING | ||
1595 | route_message->unique_id = GNUNET_htonll (msg_ctx->unique_id); | ||
1596 | #endif | ||
1597 | if (msg_ctx->bloom != NULL) | ||
1598 | GNUNET_assert (GNUNET_OK == | ||
1599 | GNUNET_CONTAINER_bloomfilter_get_raw_data (msg_ctx->bloom, | ||
1600 | route_message-> | ||
1601 | bloomfilter, | ||
1602 | DHT_BLOOM_SIZE)); | ||
1603 | memcpy (&route_message->key, &msg_ctx->key, sizeof (GNUNET_HashCode)); | ||
1604 | memcpy (&route_message[1], msg, ntohs (msg->size)); | ||
1605 | if (GNUNET_DHT_RO_RECORD_ROUTE == | ||
1606 | (msg_ctx->msg_options & GNUNET_DHT_RO_RECORD_ROUTE)) | ||
1607 | { | ||
1608 | route_message->outgoing_path_length = htonl (msg_ctx->path_history_len); | ||
1609 | /* Set pointer to start of enc_msg */ | ||
1610 | route_path = (char *) &route_message[1]; | ||
1611 | /* Offset to the end of the enc_msg */ | ||
1612 | route_path += ntohs (msg->size); | ||
1613 | /* Copy the route_path after enc_msg */ | ||
1614 | memcpy (route_path, msg_ctx->path_history, | ||
1615 | msg_ctx->path_history_len * sizeof (struct GNUNET_PeerIdentity)); | ||
1616 | } | ||
1617 | #if DEBUG_DHT > 1 | ||
1618 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1619 | "%s:%s Adding pending message size %d for peer %s\n", my_short_id, | ||
1620 | "DHT", msize, GNUNET_i2s (&peer->id)); | ||
1621 | #endif | ||
1622 | peer->pending_count++; | ||
1623 | increment_stats ("# pending messages scheduled"); | ||
1624 | GNUNET_CONTAINER_DLL_insert_after (peer->head, peer->tail, peer->tail, | ||
1625 | pending); | ||
1626 | if (peer->send_task == GNUNET_SCHEDULER_NO_TASK) | ||
1627 | peer->send_task = GNUNET_SCHEDULER_add_now (&try_core_send, peer); | ||
1628 | } | ||
1629 | |||
1630 | |||
1631 | /** | ||
1632 | * Task run to check for messages that need to be sent to a client. | ||
1633 | * | ||
1634 | * @param client a ClientList, containing the client and any messages to be sent to it | ||
1635 | */ | ||
1636 | static void | ||
1637 | process_pending_messages (struct ClientList *client) | ||
1638 | { | ||
1639 | if ((client->pending_head == NULL) || (client->transmit_handle != NULL)) | ||
1640 | return; | ||
1641 | client->transmit_handle = | ||
1642 | GNUNET_SERVER_notify_transmit_ready (client->client_handle, | ||
1643 | ntohs (client->pending_head-> | ||
1644 | msg->size), | ||
1645 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
1646 | &send_generic_reply, client); | ||
1647 | } | ||
1648 | |||
1649 | /** | ||
1650 | * Callback called as a result of issuing a GNUNET_SERVER_notify_transmit_ready | ||
1651 | * request. A ClientList is passed as closure, take the head of the list | ||
1652 | * and copy it into buf, which has the result of sending the message to the | ||
1653 | * client. | ||
1654 | * | ||
1655 | * @param cls closure to this call | ||
1656 | * @param size maximum number of bytes available to send | ||
1657 | * @param buf where to copy the actual message to | ||
1658 | * | ||
1659 | * @return the number of bytes actually copied, 0 indicates failure | ||
1660 | */ | ||
1661 | static size_t | ||
1662 | send_generic_reply (void *cls, size_t size, void *buf) | ||
1663 | { | ||
1664 | struct ClientList *client = cls; | ||
1665 | char *cbuf = buf; | ||
1666 | struct PendingMessage *reply; | ||
1667 | size_t off; | ||
1668 | size_t msize; | ||
1669 | |||
1670 | client->transmit_handle = NULL; | ||
1671 | if (buf == NULL) | ||
1672 | { | ||
1673 | /* client disconnected */ | ||
1674 | return 0; | ||
1675 | } | ||
1676 | off = 0; | ||
1677 | while ((NULL != (reply = client->pending_head)) && | ||
1678 | (size >= off + (msize = ntohs (reply->msg->size)))) | ||
1679 | { | ||
1680 | GNUNET_CONTAINER_DLL_remove (client->pending_head, client->pending_tail, | ||
1681 | reply); | ||
1682 | memcpy (&cbuf[off], reply->msg, msize); | ||
1683 | GNUNET_free (reply); | ||
1684 | off += msize; | ||
1685 | } | ||
1686 | process_pending_messages (client); | ||
1687 | #if DEBUG_DHT | ||
1688 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1689 | "Transmitted %u bytes of replies to client\n", | ||
1690 | (unsigned int) off); | ||
1691 | #endif | ||
1692 | return off; | ||
1693 | } | ||
1694 | |||
1695 | |||
1696 | /** | ||
1697 | * Add a PendingMessage to the clients list of messages to be sent | ||
1698 | * | ||
1699 | * @param client the active client to send the message to | ||
1700 | * @param pending_message the actual message to send | ||
1701 | */ | ||
1702 | static void | ||
1703 | add_pending_message (struct ClientList *client, | ||
1704 | struct PendingMessage *pending_message) | ||
1705 | { | ||
1706 | GNUNET_CONTAINER_DLL_insert_after (client->pending_head, client->pending_tail, | ||
1707 | client->pending_tail, pending_message); | ||
1708 | process_pending_messages (client); | ||
1709 | } | ||
1710 | |||
1711 | |||
1712 | /** | ||
1713 | * Called when a reply needs to be sent to a client, as | ||
1714 | * a result it found to a GET or FIND PEER request. | ||
1715 | * | ||
1716 | * @param client the client to send the reply to | ||
1717 | * @param message the encapsulated message to send | ||
1718 | * @param msg_ctx the context of the received message | ||
1719 | */ | ||
1720 | static void | ||
1721 | send_reply_to_client (struct ClientList *client, | ||
1722 | const struct GNUNET_MessageHeader *message, | ||
1723 | struct DHT_MessageContext *msg_ctx) | ||
1724 | { | ||
1725 | struct GNUNET_DHT_RouteResultMessage *reply; | ||
1726 | struct PendingMessage *pending_message; | ||
1727 | uint16_t msize; | ||
1728 | size_t tsize; | ||
1729 | char *reply_offset; | ||
1730 | |||
1731 | #if DEBUG_PATH | ||
1732 | char *path_offset; | ||
1733 | unsigned int i; | ||
1734 | #endif | ||
1735 | #if DEBUG_DHT | ||
1736 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s:%s': Sending reply to client.\n", | ||
1737 | my_short_id, "DHT"); | ||
1738 | #endif | ||
1739 | msize = ntohs (message->size); | ||
1740 | tsize = | ||
1741 | sizeof (struct GNUNET_DHT_RouteResultMessage) + msize + | ||
1742 | (msg_ctx->path_history_len * sizeof (struct GNUNET_PeerIdentity)); | ||
1743 | if (tsize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) | ||
1744 | { | ||
1745 | GNUNET_break_op (0); | ||
1746 | return; | ||
1747 | } | ||
1748 | pending_message = GNUNET_malloc (sizeof (struct PendingMessage) + tsize); | ||
1749 | pending_message->msg = (struct GNUNET_MessageHeader *) &pending_message[1]; | ||
1750 | reply = (struct GNUNET_DHT_RouteResultMessage *) &pending_message[1]; | ||
1751 | reply->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_LOCAL_ROUTE_RESULT); | ||
1752 | reply->header.size = htons (tsize); | ||
1753 | reply->outgoing_path_length = htonl (msg_ctx->path_history_len); | ||
1754 | reply->unique_id = GNUNET_htonll (msg_ctx->unique_id); | ||
1755 | memcpy (&reply->key, &msg_ctx->key, sizeof (GNUNET_HashCode)); | ||
1756 | reply_offset = (char *) &reply[1]; | ||
1757 | memcpy (&reply[1], message, msize); | ||
1758 | if (msg_ctx->path_history_len > 0) | ||
1759 | { | ||
1760 | reply_offset += msize; | ||
1761 | memcpy (reply_offset, msg_ctx->path_history, | ||
1762 | msg_ctx->path_history_len * sizeof (struct GNUNET_PeerIdentity)); | ||
1763 | } | ||
1764 | #if DEBUG_PATH | ||
1765 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1766 | "Returning message with outgoing path length %d\n", | ||
1767 | msg_ctx->path_history_len); | ||
1768 | for (i = 0; i < msg_ctx->path_history_len; i++) | ||
1769 | { | ||
1770 | path_offset = | ||
1771 | &msg_ctx->path_history[i * sizeof (struct GNUNET_PeerIdentity)]; | ||
1772 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found peer %d:%s\n", i, | ||
1773 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) path_offset)); | ||
1774 | } | ||
1775 | #endif | ||
1776 | add_pending_message (client, pending_message); | ||
1777 | } | ||
1778 | |||
1779 | /** | ||
1780 | * Consider whether or not we would like to have this peer added to | ||
1781 | * our routing table. Check whether bucket for this peer is full, | ||
1782 | * if so return negative; if not return positive. Since peers are | ||
1783 | * only added on CORE level connect, this doesn't actually add the | ||
1784 | * peer to the routing table. | ||
1785 | * | ||
1786 | * @param peer the peer we are considering adding | ||
1787 | * | ||
1788 | * @return GNUNET_YES if we want this peer, GNUNET_NO if not (bucket | ||
1789 | * already full) | ||
1790 | */ | ||
1791 | static int | ||
1792 | consider_peer (struct GNUNET_PeerIdentity *peer) | ||
1793 | { | ||
1794 | int bucket; | ||
1795 | |||
1796 | if ((GNUNET_YES == | ||
1797 | GNUNET_CONTAINER_multihashmap_contains (all_known_peers, | ||
1798 | &peer->hashPubKey)) || | ||
1799 | (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity)))) | ||
1800 | return GNUNET_NO; /* We already know this peer (are connected even!) */ | ||
1801 | bucket = find_current_bucket (&peer->hashPubKey); | ||
1802 | |||
1803 | if ((k_buckets[bucket].peers_size < bucket_size) || | ||
1804 | ((bucket == lowest_bucket) && (lowest_bucket > 0))) | ||
1805 | return GNUNET_YES; | ||
1806 | |||
1807 | return GNUNET_NO; | ||
1808 | } | ||
1809 | |||
1810 | |||
1811 | /** | ||
1812 | * Task used to remove forwarding entries, either | ||
1813 | * after timeout, when full, or on shutdown. | ||
1814 | * | ||
1815 | * @param cls the entry to remove | ||
1816 | * @param tc context, reason, etc. | ||
1817 | */ | ||
1818 | static void | ||
1819 | remove_forward_entry (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1820 | { | ||
1821 | struct DHTRouteSource *source_info = cls; | ||
1822 | struct DHTQueryRecord *record; | ||
1823 | |||
1824 | source_info = GNUNET_CONTAINER_heap_remove_node (source_info->hnode); | ||
1825 | record = source_info->record; | ||
1826 | GNUNET_CONTAINER_DLL_remove (record->head, record->tail, source_info); | ||
1827 | |||
1828 | if (record->head == NULL) /* No more entries in DLL */ | ||
1829 | { | ||
1830 | GNUNET_assert (GNUNET_YES == | ||
1831 | GNUNET_CONTAINER_multihashmap_remove (forward_list.hashmap, | ||
1832 | &record->key, record)); | ||
1833 | GNUNET_free (record); | ||
1834 | } | ||
1835 | if (source_info->find_peers_responded != NULL) | ||
1836 | GNUNET_CONTAINER_bloomfilter_free (source_info->find_peers_responded); | ||
1837 | GNUNET_free (source_info); | ||
1838 | } | ||
1839 | |||
1840 | /** | ||
1841 | * Main function that handles whether or not to route a result | ||
1842 | * message to other peers, or to send to our local client. | ||
1843 | * | ||
1844 | * @param msg the result message to be routed | ||
1845 | * @param msg_ctx context of the message we are routing | ||
1846 | * | ||
1847 | * @return the number of peers the message was routed to, | ||
1848 | * GNUNET_SYSERR on failure | ||
1849 | */ | ||
1850 | static int | ||
1851 | route_result_message (struct GNUNET_MessageHeader *msg, | ||
1852 | struct DHT_MessageContext *msg_ctx) | ||
1853 | { | ||
1854 | struct GNUNET_PeerIdentity new_peer; | ||
1855 | struct DHTQueryRecord *record; | ||
1856 | struct DHTRouteSource *pos; | ||
1857 | struct PeerInfo *peer_info; | ||
1858 | const struct GNUNET_MessageHeader *hello_msg; | ||
1859 | |||
1860 | #if DEBUG_DHT > 1 | ||
1861 | unsigned int i; | ||
1862 | #endif | ||
1863 | |||
1864 | increment_stats (STAT_RESULTS); | ||
1865 | /** | ||
1866 | * If a find peer result message is received and contains a valid | ||
1867 | * HELLO for another peer, offer it to the transport service. | ||
1868 | */ | ||
1869 | if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_DHT_FIND_PEER_RESULT) | ||
1870 | { | ||
1871 | if (ntohs (msg->size) <= sizeof (struct GNUNET_MessageHeader)) | ||
1872 | GNUNET_break_op (0); | ||
1873 | |||
1874 | hello_msg = &msg[1]; | ||
1875 | if ((ntohs (hello_msg->type) != GNUNET_MESSAGE_TYPE_HELLO) || | ||
1876 | (GNUNET_SYSERR == | ||
1877 | GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) hello_msg, | ||
1878 | &new_peer))) | ||
1879 | { | ||
1880 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1881 | "%s:%s Received non-HELLO message type in find peer result message!\n", | ||
1882 | my_short_id, "DHT"); | ||
1883 | GNUNET_break_op (0); | ||
1884 | return GNUNET_NO; | ||
1885 | } | ||
1886 | else /* We have a valid hello, and peer id stored in new_peer */ | ||
1887 | { | ||
1888 | find_peer_context.count++; | ||
1889 | increment_stats (STAT_FIND_PEER_REPLY); | ||
1890 | if (GNUNET_YES == consider_peer (&new_peer)) | ||
1891 | { | ||
1892 | increment_stats (STAT_HELLOS_PROVIDED); | ||
1893 | GNUNET_TRANSPORT_offer_hello (transport_handle, hello_msg, NULL, NULL); | ||
1894 | GNUNET_CORE_peer_request_connect (coreAPI, &new_peer, NULL, NULL); | ||
1895 | } | ||
1896 | } | ||
1897 | } | ||
1898 | |||
1899 | if (malicious_dropper == GNUNET_YES) | ||
1900 | record = NULL; | ||
1901 | else | ||
1902 | record = | ||
1903 | GNUNET_CONTAINER_multihashmap_get (forward_list.hashmap, &msg_ctx->key); | ||
1904 | |||
1905 | if (record == NULL) /* No record of this message! */ | ||
1906 | { | ||
1907 | #if DEBUG_DHT | ||
1908 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1909 | "`%s:%s': Have no record of response key %s uid %llu\n", | ||
1910 | my_short_id, "DHT", GNUNET_h2s (&msg_ctx->key), | ||
1911 | msg_ctx->unique_id); | ||
1912 | #endif | ||
1913 | #if DEBUG_DHT_ROUTING | ||
1914 | if ((debug_routes_extended) && (dhtlog_handle != NULL)) | ||
1915 | { | ||
1916 | dhtlog_handle->insert_route (NULL, msg_ctx->unique_id, DHTLOG_RESULT, | ||
1917 | msg_ctx->hop_count, GNUNET_SYSERR, | ||
1918 | &my_identity, &msg_ctx->key, &msg_ctx->peer, | ||
1919 | NULL); | ||
1920 | } | ||
1921 | #endif | ||
1922 | return 0; | ||
1923 | } | ||
1924 | |||
1925 | pos = record->head; | ||
1926 | while (pos != NULL) | ||
1927 | { | ||
1928 | #if STRICT_FORWARDING | ||
1929 | if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_DHT_FIND_PEER_RESULT) /* If we have already forwarded this peer id, don't do it again! */ | ||
1930 | { | ||
1931 | if (GNUNET_YES == | ||
1932 | GNUNET_CONTAINER_bloomfilter_test (pos->find_peers_responded, | ||
1933 | &new_peer.hashPubKey)) | ||
1934 | { | ||
1935 | increment_stats ("# find peer responses NOT forwarded (bloom match)"); | ||
1936 | pos = pos->next; | ||
1937 | continue; | ||
1938 | } | ||
1939 | else | ||
1940 | { | ||
1941 | GNUNET_CONTAINER_bloomfilter_add (pos->find_peers_responded, | ||
1942 | &new_peer.hashPubKey); | ||
1943 | } | ||
1944 | } | ||
1945 | #endif | ||
1946 | |||
1947 | if (0 == memcmp (&pos->source, &my_identity, sizeof (struct GNUNET_PeerIdentity))) /* Local client (or DHT) initiated request! */ | ||
1948 | { | ||
1949 | #if DEBUG_DHT | ||
1950 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1951 | "`%s:%s': Sending response key %s uid %llu to client\n", | ||
1952 | my_short_id, "DHT", GNUNET_h2s (&msg_ctx->key), | ||
1953 | msg_ctx->unique_id); | ||
1954 | #endif | ||
1955 | #if DEBUG_DHT_ROUTING | ||
1956 | if ((debug_routes_extended) && (dhtlog_handle != NULL)) | ||
1957 | { | ||
1958 | dhtlog_handle->insert_route (NULL, msg_ctx->unique_id, DHTLOG_RESULT, | ||
1959 | msg_ctx->hop_count, GNUNET_YES, | ||
1960 | &my_identity, &msg_ctx->key, &msg_ctx->peer, | ||
1961 | NULL); | ||
1962 | } | ||
1963 | #endif | ||
1964 | increment_stats (STAT_RESULTS_TO_CLIENT); | ||
1965 | if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_DHT_GET_RESULT) | ||
1966 | increment_stats (STAT_GET_REPLY); | ||
1967 | #if DEBUG_DHT > 1 | ||
1968 | for (i = 0; i < msg_ctx->path_history_len; i++) | ||
1969 | { | ||
1970 | char *path_offset; | ||
1971 | |||
1972 | path_offset = | ||
1973 | &msg_ctx->path_history[i * sizeof (struct GNUNET_PeerIdentity)]; | ||
1974 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1975 | "(before client) Key %s Found peer %d:%s\n", | ||
1976 | GNUNET_h2s (&msg_ctx->key), i, | ||
1977 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) path_offset)); | ||
1978 | } | ||
1979 | #endif | ||
1980 | send_reply_to_client (pos->client, msg, msg_ctx); | ||
1981 | } | ||
1982 | else /* Send to peer */ | ||
1983 | { | ||
1984 | peer_info = find_peer_by_id (&pos->source); | ||
1985 | if (peer_info == NULL) /* Didn't find the peer in our routing table, perhaps peer disconnected! */ | ||
1986 | { | ||
1987 | pos = pos->next; | ||
1988 | continue; | ||
1989 | } | ||
1990 | #if DEBUG_DHT | ||
1991 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1992 | "`%s:%s': Forwarding response key %s uid %llu to peer %s\n", | ||
1993 | my_short_id, "DHT", GNUNET_h2s (&msg_ctx->key), | ||
1994 | msg_ctx->unique_id, GNUNET_i2s (&peer_info->id)); | ||
1995 | #endif | ||
1996 | #if DEBUG_DHT_ROUTING | ||
1997 | if ((debug_routes_extended) && (dhtlog_handle != NULL)) | ||
1998 | { | ||
1999 | dhtlog_handle->insert_route (NULL, msg_ctx->unique_id, DHTLOG_RESULT, | ||
2000 | msg_ctx->hop_count, GNUNET_NO, | ||
2001 | &my_identity, &msg_ctx->key, | ||
2002 | &msg_ctx->peer, &pos->source); | ||
2003 | } | ||
2004 | #endif | ||
2005 | forward_result_message (msg, peer_info, msg_ctx); | ||
2006 | /* Try removing forward entries after sending once, only allows ONE response per request */ | ||
2007 | if (pos->delete_task != GNUNET_SCHEDULER_NO_TASK) | ||
2008 | { | ||
2009 | GNUNET_SCHEDULER_cancel (pos->delete_task); | ||
2010 | pos->delete_task = | ||
2011 | GNUNET_SCHEDULER_add_now (&remove_forward_entry, pos); | ||
2012 | } | ||
2013 | } | ||
2014 | pos = pos->next; | ||
2015 | } | ||
2016 | return 0; | ||
2017 | } | ||
2018 | |||
2019 | |||
2020 | /** | ||
2021 | * Iterator for local get request results, | ||
2022 | * | ||
2023 | * @param cls closure for iterator, a DatacacheGetContext | ||
2024 | * @param exp when does this value expire? | ||
2025 | * @param key the key this data is stored under | ||
2026 | * @param size the size of the data identified by key | ||
2027 | * @param data the actual data | ||
2028 | * @param type the type of the data | ||
2029 | * | ||
2030 | * @return GNUNET_OK to continue iteration, anything else | ||
2031 | * to stop iteration. | ||
2032 | */ | ||
2033 | static int | ||
2034 | datacache_get_iterator (void *cls, struct GNUNET_TIME_Absolute exp, | ||
2035 | const GNUNET_HashCode * key, size_t size, | ||
2036 | const char *data, enum GNUNET_BLOCK_Type type) | ||
2037 | { | ||
2038 | struct DHT_MessageContext *msg_ctx = cls; | ||
2039 | struct DHT_MessageContext new_msg_ctx; | ||
2040 | struct GNUNET_DHT_GetResultMessage *get_result; | ||
2041 | enum GNUNET_BLOCK_EvaluationResult eval; | ||
2042 | const struct DHTPutEntry *put_entry; | ||
2043 | int get_size; | ||
2044 | char *path_offset; | ||
2045 | |||
2046 | #if DEBUG_PATH | ||
2047 | unsigned int i; | ||
2048 | #endif | ||
2049 | |||
2050 | #if DEBUG_DHT | ||
2051 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2052 | "`%s:%s': Received `%s' response from datacache\n", my_short_id, | ||
2053 | "DHT", "GET"); | ||
2054 | #endif | ||
2055 | |||
2056 | put_entry = (const struct DHTPutEntry *) data; | ||
2057 | |||
2058 | if (size != | ||
2059 | sizeof (struct DHTPutEntry) + put_entry->data_size + | ||
2060 | (put_entry->path_length * sizeof (struct GNUNET_PeerIdentity))) | ||
2061 | { | ||
2062 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2063 | "Path + data size doesn't add up for data inserted into datacache!\nData size %d, path length %d, expected %d, got %d\n", | ||
2064 | put_entry->data_size, put_entry->path_length, | ||
2065 | sizeof (struct DHTPutEntry) + put_entry->data_size + | ||
2066 | (put_entry->path_length * sizeof (struct GNUNET_PeerIdentity)), | ||
2067 | size); | ||
2068 | msg_ctx->do_forward = GNUNET_NO; | ||
2069 | return GNUNET_OK; | ||
2070 | } | ||
2071 | |||
2072 | eval = | ||
2073 | GNUNET_BLOCK_evaluate (block_context, type, key, &msg_ctx->reply_bf, | ||
2074 | msg_ctx->reply_bf_mutator, msg_ctx->xquery, | ||
2075 | msg_ctx->xquery_size, &put_entry[1], | ||
2076 | put_entry->data_size); | ||
2077 | |||
2078 | switch (eval) | ||
2079 | { | ||
2080 | case GNUNET_BLOCK_EVALUATION_OK_LAST: | ||
2081 | msg_ctx->do_forward = GNUNET_NO; | ||
2082 | case GNUNET_BLOCK_EVALUATION_OK_MORE: | ||
2083 | memcpy (&new_msg_ctx, msg_ctx, sizeof (struct DHT_MessageContext)); | ||
2084 | if (GNUNET_DHT_RO_RECORD_ROUTE == | ||
2085 | (msg_ctx->msg_options & GNUNET_DHT_RO_RECORD_ROUTE)) | ||
2086 | { | ||
2087 | new_msg_ctx.msg_options = GNUNET_DHT_RO_RECORD_ROUTE; | ||
2088 | #if DEBUG_PATH | ||
2089 | for (i = 0; i < new_msg_ctx.path_history_len; i++) | ||
2090 | { | ||
2091 | path_offset = | ||
2092 | &new_msg_ctx.path_history[i * sizeof (struct GNUNET_PeerIdentity)]; | ||
2093 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2094 | "(get_iterator) Key %s Found peer %d:%s\n", | ||
2095 | GNUNET_h2s (&msg_ctx->key), i, | ||
2096 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) path_offset)); | ||
2097 | } | ||
2098 | #endif | ||
2099 | } | ||
2100 | |||
2101 | get_size = | ||
2102 | sizeof (struct GNUNET_DHT_GetResultMessage) + put_entry->data_size + | ||
2103 | (put_entry->path_length * sizeof (struct GNUNET_PeerIdentity)); | ||
2104 | get_result = GNUNET_malloc (get_size); | ||
2105 | get_result->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_GET_RESULT); | ||
2106 | get_result->header.size = htons (get_size); | ||
2107 | get_result->expiration = GNUNET_TIME_absolute_hton (exp); | ||
2108 | get_result->type = htons (type); | ||
2109 | get_result->put_path_length = htons (put_entry->path_length); | ||
2110 | path_offset = (char *) &put_entry[1]; | ||
2111 | path_offset += put_entry->data_size; | ||
2112 | #if DEBUG_PATH | ||
2113 | for (i = 0; i < put_entry->path_length; i++) | ||
2114 | { | ||
2115 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2116 | "(get_iterator PUT path) Key %s Found peer %d:%s\n", | ||
2117 | GNUNET_h2s (&msg_ctx->key), i, | ||
2118 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) | ||
2119 | &path_offset[i * | ||
2120 | sizeof (struct | ||
2121 | GNUNET_PeerIdentity)])); | ||
2122 | } | ||
2123 | #endif | ||
2124 | /* Copy the actual data and the path_history to the end of the get result */ | ||
2125 | memcpy (&get_result[1], &put_entry[1], | ||
2126 | put_entry->data_size + | ||
2127 | (put_entry->path_length * sizeof (struct GNUNET_PeerIdentity))); | ||
2128 | new_msg_ctx.peer = my_identity; | ||
2129 | new_msg_ctx.bloom = NULL; | ||
2130 | new_msg_ctx.hop_count = 0; | ||
2131 | new_msg_ctx.importance = DHT_DEFAULT_P2P_IMPORTANCE + 2; /* Make result routing a higher priority */ | ||
2132 | new_msg_ctx.timeout = DHT_DEFAULT_P2P_TIMEOUT; | ||
2133 | increment_stats (STAT_GET_RESPONSE_START); | ||
2134 | route_result_message (&get_result->header, &new_msg_ctx); | ||
2135 | GNUNET_free (get_result); | ||
2136 | break; | ||
2137 | case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE: | ||
2138 | #if DEBUG_DHT | ||
2139 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s:%s': Duplicate block error\n", | ||
2140 | my_short_id, "DHT"); | ||
2141 | #endif | ||
2142 | break; | ||
2143 | case GNUNET_BLOCK_EVALUATION_RESULT_INVALID: | ||
2144 | #if DEBUG_DHT | ||
2145 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "`%s:%s': Invalid request error\n", | ||
2146 | my_short_id, "DHT"); | ||
2147 | #endif | ||
2148 | break; | ||
2149 | case GNUNET_BLOCK_EVALUATION_REQUEST_VALID: | ||
2150 | #if DEBUG_DHT | ||
2151 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2152 | "`%s:%s': Valid request, no results.\n", my_short_id, "DHT"); | ||
2153 | #endif | ||
2154 | GNUNET_break (0); | ||
2155 | break; | ||
2156 | case GNUNET_BLOCK_EVALUATION_REQUEST_INVALID: | ||
2157 | GNUNET_break_op (0); | ||
2158 | msg_ctx->do_forward = GNUNET_NO; | ||
2159 | break; | ||
2160 | case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED: | ||
2161 | #if DEBUG_DHT | ||
2162 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2163 | "`%s:%s': Unsupported block type (%u) in response!\n", | ||
2164 | my_short_id, "DHT", type); | ||
2165 | #endif | ||
2166 | /* msg_ctx->do_forward = GNUNET_NO; // not sure... */ | ||
2167 | break; | ||
2168 | } | ||
2169 | return GNUNET_OK; | ||
2170 | } | ||
2171 | |||
2172 | |||
2173 | /** | ||
2174 | * Main function that handles whether or not to route a message to other | ||
2175 | * peers. | ||
2176 | * | ||
2177 | * @param msg the message to be routed | ||
2178 | * @param msg_ctx the context containing all pertinent information about the message | ||
2179 | */ | ||
2180 | static void | ||
2181 | route_message (const struct GNUNET_MessageHeader *msg, | ||
2182 | struct DHT_MessageContext *msg_ctx); | ||
2183 | |||
2184 | |||
2185 | /** | ||
2186 | * Server handler for all dht get requests, look for data, | ||
2187 | * if found, send response either to clients or other peers. | ||
2188 | * | ||
2189 | * @param msg the actual get message | ||
2190 | * @param msg_ctx struct containing pertinent information about the get request | ||
2191 | * | ||
2192 | * @return number of items found for GET request | ||
2193 | */ | ||
2194 | static unsigned int | ||
2195 | handle_dht_get (const struct GNUNET_MessageHeader *msg, | ||
2196 | struct DHT_MessageContext *msg_ctx) | ||
2197 | { | ||
2198 | const struct GNUNET_DHT_GetMessage *get_msg; | ||
2199 | uint16_t msize; | ||
2200 | uint16_t bf_size; | ||
2201 | unsigned int results; | ||
2202 | const char *end; | ||
2203 | enum GNUNET_BLOCK_Type type; | ||
2204 | |||
2205 | msize = ntohs (msg->size); | ||
2206 | if (msize < sizeof (struct GNUNET_DHT_GetMessage)) | ||
2207 | { | ||
2208 | GNUNET_break (0); | ||
2209 | return 0; | ||
2210 | } | ||
2211 | get_msg = (const struct GNUNET_DHT_GetMessage *) msg; | ||
2212 | bf_size = ntohs (get_msg->bf_size); | ||
2213 | msg_ctx->xquery_size = ntohs (get_msg->xquery_size); | ||
2214 | msg_ctx->reply_bf_mutator = get_msg->bf_mutator; | ||
2215 | if (msize != | ||
2216 | sizeof (struct GNUNET_DHT_GetMessage) + bf_size + msg_ctx->xquery_size) | ||
2217 | { | ||
2218 | GNUNET_break_op (0); | ||
2219 | return 0; | ||
2220 | } | ||
2221 | end = (const char *) &get_msg[1]; | ||
2222 | if (msg_ctx->xquery_size == 0) | ||
2223 | { | ||
2224 | msg_ctx->xquery = NULL; | ||
2225 | } | ||
2226 | else | ||
2227 | { | ||
2228 | msg_ctx->xquery = (const void *) end; | ||
2229 | end += msg_ctx->xquery_size; | ||
2230 | } | ||
2231 | if (bf_size == 0) | ||
2232 | { | ||
2233 | msg_ctx->reply_bf = NULL; | ||
2234 | } | ||
2235 | else | ||
2236 | { | ||
2237 | msg_ctx->reply_bf = | ||
2238 | GNUNET_CONTAINER_bloomfilter_init (end, bf_size, | ||
2239 | GNUNET_DHT_GET_BLOOMFILTER_K); | ||
2240 | } | ||
2241 | type = (enum GNUNET_BLOCK_Type) ntohl (get_msg->type); | ||
2242 | #if DEBUG_DHT | ||
2243 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2244 | "`%s:%s': Received `%s' request, message type %u, key %s, uid %llu\n", | ||
2245 | my_short_id, "DHT", "GET", type, GNUNET_h2s (&msg_ctx->key), | ||
2246 | msg_ctx->unique_id); | ||
2247 | #endif | ||
2248 | increment_stats (STAT_GETS); | ||
2249 | results = 0; | ||
2250 | #if HAVE_MALICIOUS | ||
2251 | if (type == GNUNET_BLOCK_DHT_MALICIOUS_MESSAGE_TYPE) | ||
2252 | { | ||
2253 | GNUNET_CONTAINER_bloomfilter_free (msg_ctx->reply_bf); | ||
2254 | return results; | ||
2255 | } | ||
2256 | #endif | ||
2257 | msg_ctx->do_forward = GNUNET_YES; | ||
2258 | if (datacache != NULL) | ||
2259 | results = | ||
2260 | GNUNET_DATACACHE_get (datacache, &msg_ctx->key, type, | ||
2261 | &datacache_get_iterator, msg_ctx); | ||
2262 | #if DEBUG_DHT | ||
2263 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2264 | "`%s:%s': Found %d results for `%s' request uid %llu\n", | ||
2265 | my_short_id, "DHT", results, "GET", msg_ctx->unique_id); | ||
2266 | #endif | ||
2267 | if (results >= 1) | ||
2268 | { | ||
2269 | #if DEBUG_DHT_ROUTING | ||
2270 | if ((debug_routes) && (dhtlog_handle != NULL)) | ||
2271 | { | ||
2272 | dhtlog_handle->insert_query (NULL, msg_ctx->unique_id, DHTLOG_GET, | ||
2273 | msg_ctx->hop_count, GNUNET_YES, &my_identity, | ||
2274 | &msg_ctx->key); | ||
2275 | } | ||
2276 | |||
2277 | if ((debug_routes_extended) && (dhtlog_handle != NULL)) | ||
2278 | { | ||
2279 | dhtlog_handle->insert_route (NULL, msg_ctx->unique_id, DHTLOG_ROUTE, | ||
2280 | msg_ctx->hop_count, GNUNET_YES, &my_identity, | ||
2281 | &msg_ctx->key, &msg_ctx->peer, NULL); | ||
2282 | } | ||
2283 | #endif | ||
2284 | } | ||
2285 | else | ||
2286 | { | ||
2287 | /* check query valid */ | ||
2288 | if (GNUNET_BLOCK_EVALUATION_REQUEST_INVALID == | ||
2289 | GNUNET_BLOCK_evaluate (block_context, type, &msg_ctx->key, | ||
2290 | &msg_ctx->reply_bf, msg_ctx->reply_bf_mutator, | ||
2291 | msg_ctx->xquery, msg_ctx->xquery_size, NULL, 0)) | ||
2292 | { | ||
2293 | GNUNET_break_op (0); | ||
2294 | msg_ctx->do_forward = GNUNET_NO; | ||
2295 | } | ||
2296 | } | ||
2297 | |||
2298 | if (msg_ctx->hop_count == 0) /* Locally initiated request */ | ||
2299 | { | ||
2300 | #if DEBUG_DHT_ROUTING | ||
2301 | if ((debug_routes) && (dhtlog_handle != NULL)) | ||
2302 | { | ||
2303 | dhtlog_handle->insert_query (NULL, msg_ctx->unique_id, DHTLOG_GET, | ||
2304 | msg_ctx->hop_count, GNUNET_NO, &my_identity, | ||
2305 | &msg_ctx->key); | ||
2306 | } | ||
2307 | #endif | ||
2308 | } | ||
2309 | if (msg_ctx->do_forward == GNUNET_YES) | ||
2310 | route_message (msg, msg_ctx); | ||
2311 | GNUNET_CONTAINER_bloomfilter_free (msg_ctx->reply_bf); | ||
2312 | return results; | ||
2313 | } | ||
2314 | |||
2315 | |||
2316 | static void | ||
2317 | remove_recent_find_peer (void *cls, | ||
2318 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
2319 | { | ||
2320 | GNUNET_HashCode *key = cls; | ||
2321 | |||
2322 | GNUNET_assert (GNUNET_YES == | ||
2323 | GNUNET_CONTAINER_multihashmap_remove | ||
2324 | (recent_find_peer_requests, key, NULL)); | ||
2325 | GNUNET_free (key); | ||
2326 | } | ||
2327 | |||
2328 | |||
2329 | /** | ||
2330 | * Server handler for initiating local dht find peer requests | ||
2331 | * | ||
2332 | * @param find_msg the actual find peer message | ||
2333 | * @param msg_ctx struct containing pertinent information about the request | ||
2334 | * | ||
2335 | */ | ||
2336 | static void | ||
2337 | handle_dht_find_peer (const struct GNUNET_MessageHeader *find_msg, | ||
2338 | struct DHT_MessageContext *msg_ctx) | ||
2339 | { | ||
2340 | struct GNUNET_MessageHeader *find_peer_result; | ||
2341 | struct GNUNET_DHT_FindPeerMessage *find_peer_message; | ||
2342 | struct DHT_MessageContext *new_msg_ctx; | ||
2343 | struct GNUNET_CONTAINER_BloomFilter *incoming_bloom; | ||
2344 | size_t hello_size; | ||
2345 | size_t tsize; | ||
2346 | GNUNET_HashCode *recent_hash; | ||
2347 | struct GNUNET_MessageHeader *other_hello; | ||
2348 | size_t other_hello_size; | ||
2349 | struct GNUNET_PeerIdentity peer_id; | ||
2350 | |||
2351 | find_peer_message = (struct GNUNET_DHT_FindPeerMessage *) find_msg; | ||
2352 | GNUNET_break_op (ntohs (find_msg->size) >= | ||
2353 | (sizeof (struct GNUNET_DHT_FindPeerMessage))); | ||
2354 | if (ntohs (find_msg->size) < sizeof (struct GNUNET_DHT_FindPeerMessage)) | ||
2355 | return; | ||
2356 | other_hello = NULL; | ||
2357 | other_hello_size = 0; | ||
2358 | if (ntohs (find_msg->size) > sizeof (struct GNUNET_DHT_FindPeerMessage)) | ||
2359 | { | ||
2360 | other_hello_size = | ||
2361 | ntohs (find_msg->size) - sizeof (struct GNUNET_DHT_FindPeerMessage); | ||
2362 | other_hello = GNUNET_malloc (other_hello_size); | ||
2363 | memcpy (other_hello, &find_peer_message[1], other_hello_size); | ||
2364 | if ((GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) other_hello) == 0) | ||
2365 | || (GNUNET_OK != | ||
2366 | GNUNET_HELLO_get_id ((struct GNUNET_HELLO_Message *) other_hello, | ||
2367 | &peer_id))) | ||
2368 | { | ||
2369 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2370 | "Received invalid HELLO message in find peer request!\n"); | ||
2371 | GNUNET_free (other_hello); | ||
2372 | return; | ||
2373 | } | ||
2374 | #if FIND_PEER_WITH_HELLO | ||
2375 | if (GNUNET_YES == consider_peer (&peer_id)) | ||
2376 | { | ||
2377 | increment_stats (STAT_HELLOS_PROVIDED); | ||
2378 | GNUNET_TRANSPORT_offer_hello (transport_handle, other_hello, NULL, NULL); | ||
2379 | GNUNET_CORE_peer_request_connect (coreAPI, &peer_id, NULL, NULL); | ||
2380 | route_message (find_msg, msg_ctx); | ||
2381 | GNUNET_free (other_hello); | ||
2382 | return; | ||
2383 | } | ||
2384 | else /* We don't want this peer! */ | ||
2385 | { | ||
2386 | route_message (find_msg, msg_ctx); | ||
2387 | GNUNET_free (other_hello); | ||
2388 | return; | ||
2389 | } | ||
2390 | #endif | ||
2391 | } | ||
2392 | |||
2393 | #if DEBUG_DHT | ||
2394 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2395 | "`%s:%s': Received `%s' request from client, key %s (msg size %d, we expected %d)\n", | ||
2396 | my_short_id, "DHT", "FIND PEER", GNUNET_h2s (&msg_ctx->key), | ||
2397 | ntohs (find_msg->size), sizeof (struct GNUNET_MessageHeader)); | ||
2398 | #endif | ||
2399 | if (my_hello == NULL) | ||
2400 | { | ||
2401 | #if DEBUG_DHT | ||
2402 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2403 | "`%s': Our HELLO is null, can't return.\n", "DHT"); | ||
2404 | #endif | ||
2405 | GNUNET_free_non_null (other_hello); | ||
2406 | route_message (find_msg, msg_ctx); | ||
2407 | return; | ||
2408 | } | ||
2409 | |||
2410 | incoming_bloom = | ||
2411 | GNUNET_CONTAINER_bloomfilter_init (find_peer_message->bloomfilter, | ||
2412 | DHT_BLOOM_SIZE, DHT_BLOOM_K); | ||
2413 | if (GNUNET_YES == | ||
2414 | GNUNET_CONTAINER_bloomfilter_test (incoming_bloom, | ||
2415 | &my_identity.hashPubKey)) | ||
2416 | { | ||
2417 | increment_stats (STAT_BLOOM_FIND_PEER); | ||
2418 | GNUNET_CONTAINER_bloomfilter_free (incoming_bloom); | ||
2419 | GNUNET_free_non_null (other_hello); | ||
2420 | route_message (find_msg, msg_ctx); | ||
2421 | return; /* We match the bloomfilter, do not send a response to this peer (they likely already know us!) */ | ||
2422 | } | ||
2423 | GNUNET_CONTAINER_bloomfilter_free (incoming_bloom); | ||
2424 | |||
2425 | #if RESTRICT_FIND_PEER | ||
2426 | |||
2427 | /** | ||
2428 | * Ignore any find peer requests from a peer we have seen very recently. | ||
2429 | */ | ||
2430 | if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (recent_find_peer_requests, &msg_ctx->key)) /* We have recently responded to a find peer request for this peer! */ | ||
2431 | { | ||
2432 | increment_stats ("# dht find peer requests ignored (recently seen!)"); | ||
2433 | GNUNET_free_non_null (other_hello); | ||
2434 | return; | ||
2435 | } | ||
2436 | |||
2437 | /** | ||
2438 | * Use this check to only allow the peer to respond to find peer requests if | ||
2439 | * it would be beneficial to have the requesting peer in this peers routing | ||
2440 | * table. Can be used to thwart peers flooding the network with find peer | ||
2441 | * requests that we don't care about. However, if a new peer is joining | ||
2442 | * the network and has no other peers this is a problem (assume all buckets | ||
2443 | * full, no one will respond!). | ||
2444 | */ | ||
2445 | memcpy (&peer_id.hashPubKey, &msg_ctx->key, sizeof (GNUNET_HashCode)); | ||
2446 | if (GNUNET_NO == consider_peer (&peer_id)) | ||
2447 | { | ||
2448 | increment_stats ("# dht find peer requests ignored (do not need!)"); | ||
2449 | GNUNET_free_non_null (other_hello); | ||
2450 | route_message (find_msg, msg_ctx); | ||
2451 | return; | ||
2452 | } | ||
2453 | #endif | ||
2454 | |||
2455 | recent_hash = GNUNET_malloc (sizeof (GNUNET_HashCode)); | ||
2456 | memcpy (recent_hash, &msg_ctx->key, sizeof (GNUNET_HashCode)); | ||
2457 | if (GNUNET_SYSERR != | ||
2458 | GNUNET_CONTAINER_multihashmap_put (recent_find_peer_requests, | ||
2459 | &msg_ctx->key, NULL, | ||
2460 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
2461 | { | ||
2462 | #if DEBUG_DHT | ||
2463 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2464 | "Adding recent remove task for key `%s`!\n", | ||
2465 | GNUNET_h2s (&msg_ctx->key)); | ||
2466 | #endif | ||
2467 | /* Only add a task if there wasn't one for this key already! */ | ||
2468 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
2469 | (GNUNET_TIME_UNIT_SECONDS, 30), | ||
2470 | &remove_recent_find_peer, recent_hash); | ||
2471 | } | ||
2472 | else | ||
2473 | { | ||
2474 | GNUNET_free (recent_hash); | ||
2475 | #if DEBUG_DHT | ||
2476 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2477 | "Received duplicate find peer request too soon!\n"); | ||
2478 | #endif | ||
2479 | } | ||
2480 | |||
2481 | /* Simplistic find_peer functionality, always return our hello */ | ||
2482 | hello_size = ntohs (my_hello->size); | ||
2483 | tsize = hello_size + sizeof (struct GNUNET_MessageHeader); | ||
2484 | |||
2485 | if (tsize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) | ||
2486 | { | ||
2487 | GNUNET_break_op (0); | ||
2488 | GNUNET_free_non_null (other_hello); | ||
2489 | return; | ||
2490 | } | ||
2491 | |||
2492 | find_peer_result = GNUNET_malloc (tsize); | ||
2493 | find_peer_result->type = htons (GNUNET_MESSAGE_TYPE_DHT_FIND_PEER_RESULT); | ||
2494 | find_peer_result->size = htons (tsize); | ||
2495 | memcpy (&find_peer_result[1], my_hello, hello_size); | ||
2496 | #if DEBUG_DHT | ||
2497 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2498 | "`%s': Sending hello size %d to requesting peer.\n", "DHT", | ||
2499 | hello_size); | ||
2500 | #endif | ||
2501 | |||
2502 | new_msg_ctx = GNUNET_malloc (sizeof (struct DHT_MessageContext)); | ||
2503 | memcpy (new_msg_ctx, msg_ctx, sizeof (struct DHT_MessageContext)); | ||
2504 | new_msg_ctx->peer = my_identity; | ||
2505 | new_msg_ctx->bloom = | ||
2506 | GNUNET_CONTAINER_bloomfilter_init (NULL, DHT_BLOOM_SIZE, DHT_BLOOM_K); | ||
2507 | new_msg_ctx->hop_count = 0; | ||
2508 | new_msg_ctx->importance = DHT_DEFAULT_P2P_IMPORTANCE + 2; /* Make find peer requests a higher priority */ | ||
2509 | new_msg_ctx->timeout = DHT_DEFAULT_P2P_TIMEOUT; | ||
2510 | increment_stats (STAT_FIND_PEER_ANSWER); | ||
2511 | if (GNUNET_DHT_RO_RECORD_ROUTE == | ||
2512 | (msg_ctx->msg_options & GNUNET_DHT_RO_RECORD_ROUTE)) | ||
2513 | { | ||
2514 | new_msg_ctx->msg_options = GNUNET_DHT_RO_RECORD_ROUTE; | ||
2515 | new_msg_ctx->path_history_len = msg_ctx->path_history_len; | ||
2516 | /* Assign to previous msg_ctx path history, caller should free after our return */ | ||
2517 | new_msg_ctx->path_history = msg_ctx->path_history; | ||
2518 | } | ||
2519 | route_result_message (find_peer_result, new_msg_ctx); | ||
2520 | GNUNET_free (new_msg_ctx); | ||
2521 | #if DEBUG_DHT_ROUTING | ||
2522 | if ((debug_routes) && (dhtlog_handle != NULL)) | ||
2523 | { | ||
2524 | dhtlog_handle->insert_query (NULL, msg_ctx->unique_id, DHTLOG_FIND_PEER, | ||
2525 | msg_ctx->hop_count, GNUNET_YES, &my_identity, | ||
2526 | &msg_ctx->key); | ||
2527 | } | ||
2528 | #endif | ||
2529 | GNUNET_free_non_null (other_hello); | ||
2530 | GNUNET_free (find_peer_result); | ||
2531 | route_message (find_msg, msg_ctx); | ||
2532 | } | ||
2533 | |||
2534 | |||
2535 | /** | ||
2536 | * Server handler for initiating local dht put requests | ||
2537 | * | ||
2538 | * @param msg the actual put message | ||
2539 | * @param msg_ctx struct containing pertinent information about the request | ||
2540 | */ | ||
2541 | static void | ||
2542 | handle_dht_put (const struct GNUNET_MessageHeader *msg, | ||
2543 | struct DHT_MessageContext *msg_ctx) | ||
2544 | { | ||
2545 | const struct GNUNET_DHT_PutMessage *put_msg; | ||
2546 | struct DHTPutEntry *put_entry; | ||
2547 | unsigned int put_size; | ||
2548 | char *path_offset; | ||
2549 | enum GNUNET_BLOCK_Type put_type; | ||
2550 | size_t data_size; | ||
2551 | int ret; | ||
2552 | GNUNET_HashCode key; | ||
2553 | struct DHTQueryRecord *record; | ||
2554 | |||
2555 | GNUNET_assert (ntohs (msg->size) >= sizeof (struct GNUNET_DHT_PutMessage)); | ||
2556 | |||
2557 | put_msg = (const struct GNUNET_DHT_PutMessage *) msg; | ||
2558 | put_type = (enum GNUNET_BLOCK_Type) ntohl (put_msg->type); | ||
2559 | #if HAVE_MALICIOUS | ||
2560 | if (put_type == GNUNET_BLOCK_DHT_MALICIOUS_MESSAGE_TYPE) | ||
2561 | { | ||
2562 | #if DEBUG_DHT_ROUTING | ||
2563 | if ((debug_routes_extended) && (dhtlog_handle != NULL)) | ||
2564 | { | ||
2565 | /** Log routes that die due to high load! */ | ||
2566 | dhtlog_handle->insert_route (NULL, msg_ctx->unique_id, DHTLOG_ROUTE, | ||
2567 | msg_ctx->hop_count, GNUNET_SYSERR, | ||
2568 | &my_identity, &msg_ctx->key, &msg_ctx->peer, | ||
2569 | NULL); | ||
2570 | } | ||
2571 | #endif | ||
2572 | return; | ||
2573 | } | ||
2574 | #endif | ||
2575 | data_size = | ||
2576 | ntohs (put_msg->header.size) - sizeof (struct GNUNET_DHT_PutMessage); | ||
2577 | ret = | ||
2578 | GNUNET_BLOCK_get_key (block_context, put_type, &put_msg[1], data_size, | ||
2579 | &key); | ||
2580 | if (GNUNET_NO == ret) | ||
2581 | { | ||
2582 | #if DEBUG_DHT_ROUTING | ||
2583 | if ((debug_routes_extended) && (dhtlog_handle != NULL)) | ||
2584 | { | ||
2585 | dhtlog_handle->insert_route (NULL, msg_ctx->unique_id, DHTLOG_ROUTE, | ||
2586 | msg_ctx->hop_count, GNUNET_SYSERR, | ||
2587 | &my_identity, &msg_ctx->key, &msg_ctx->peer, | ||
2588 | NULL); | ||
2589 | } | ||
2590 | #endif | ||
2591 | /* invalid reply */ | ||
2592 | GNUNET_break_op (0); | ||
2593 | return; | ||
2594 | } | ||
2595 | if ((GNUNET_YES == ret) && | ||
2596 | (0 != memcmp (&key, &msg_ctx->key, sizeof (GNUNET_HashCode)))) | ||
2597 | { | ||
2598 | #if DEBUG_DHT_ROUTING | ||
2599 | if ((debug_routes_extended) && (dhtlog_handle != NULL)) | ||
2600 | { | ||
2601 | dhtlog_handle->insert_route (NULL, msg_ctx->unique_id, DHTLOG_ROUTE, | ||
2602 | msg_ctx->hop_count, GNUNET_SYSERR, | ||
2603 | &my_identity, &msg_ctx->key, &msg_ctx->peer, | ||
2604 | NULL); | ||
2605 | } | ||
2606 | #endif | ||
2607 | /* invalid wrapper: key mismatch! */ | ||
2608 | GNUNET_break_op (0); | ||
2609 | return; | ||
2610 | } | ||
2611 | /* ret == GNUNET_SYSERR means that there is no known relationship between | ||
2612 | * data and the key, so we cannot check it */ | ||
2613 | #if DEBUG_DHT | ||
2614 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2615 | "`%s:%s': Received `%s' request (inserting data!), message type %d, key %s, uid %llu\n", | ||
2616 | my_short_id, "DHT", "PUT", put_type, GNUNET_h2s (&msg_ctx->key), | ||
2617 | msg_ctx->unique_id); | ||
2618 | #endif | ||
2619 | #if DEBUG_DHT_ROUTING | ||
2620 | if (msg_ctx->hop_count == 0) /* Locally initiated request */ | ||
2621 | { | ||
2622 | if ((debug_routes) && (dhtlog_handle != NULL)) | ||
2623 | { | ||
2624 | dhtlog_handle->insert_query (NULL, msg_ctx->unique_id, DHTLOG_PUT, | ||
2625 | msg_ctx->hop_count, GNUNET_NO, &my_identity, | ||
2626 | &msg_ctx->key); | ||
2627 | } | ||
2628 | } | ||
2629 | #endif | ||
2630 | |||
2631 | record = GNUNET_CONTAINER_multihashmap_get(forward_list.hashmap, | ||
2632 | &msg_ctx->key); | ||
2633 | if (NULL != record) | ||
2634 | { | ||
2635 | struct DHTRouteSource *pos; | ||
2636 | struct GNUNET_DHT_GetResultMessage *get_result; | ||
2637 | struct DHT_MessageContext new_msg_ctx; | ||
2638 | size_t get_size; | ||
2639 | |||
2640 | pos = record->head; | ||
2641 | while (pos != NULL) | ||
2642 | { | ||
2643 | /* TODO: do only for local started requests? or also for remote peers? */ | ||
2644 | /* TODO: include this in statistics? under what? */ | ||
2645 | /* TODO: reverse order of path_history? */ | ||
2646 | if (NULL == pos->client) | ||
2647 | { | ||
2648 | pos = pos->next; | ||
2649 | continue; | ||
2650 | } | ||
2651 | |||
2652 | memcpy (&new_msg_ctx, msg_ctx, sizeof (struct DHT_MessageContext)); | ||
2653 | if (GNUNET_DHT_RO_RECORD_ROUTE == | ||
2654 | (msg_ctx->msg_options & GNUNET_DHT_RO_RECORD_ROUTE)) | ||
2655 | { | ||
2656 | new_msg_ctx.msg_options = GNUNET_DHT_RO_RECORD_ROUTE; | ||
2657 | #if DEBUG_PATH | ||
2658 | for (i = 0; i < new_msg_ctx.path_history_len; i++) | ||
2659 | { | ||
2660 | path_offset = | ||
2661 | &new_msg_ctx.path_history[i * sizeof (struct GNUNET_PeerIdentity)]; | ||
2662 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2663 | "(put for active get) Key %s Found peer %d:%s\n", | ||
2664 | GNUNET_h2s (&msg_ctx->key), i, | ||
2665 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) path_offset)); | ||
2666 | } | ||
2667 | #endif | ||
2668 | } | ||
2669 | |||
2670 | get_size = | ||
2671 | sizeof (struct GNUNET_DHT_GetResultMessage) + data_size + | ||
2672 | (msg_ctx->path_history_len * sizeof (struct GNUNET_PeerIdentity)); | ||
2673 | get_result = GNUNET_malloc (get_size); | ||
2674 | get_result->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_GET_RESULT); | ||
2675 | get_result->header.size = htons (get_size); | ||
2676 | get_result->expiration = put_msg->expiration; | ||
2677 | get_result->type = put_msg->type; | ||
2678 | get_result->put_path_length = htons (msg_ctx->path_history_len); | ||
2679 | |||
2680 | /* Copy the actual data and the path_history to the end of the get result */ | ||
2681 | memcpy (&get_result[1], &put_msg[1], data_size); | ||
2682 | path_offset = (char *) &get_result[1]; | ||
2683 | path_offset += data_size; | ||
2684 | memcpy (path_offset, msg_ctx->path_history, | ||
2685 | msg_ctx->path_history_len * sizeof (struct GNUNET_PeerIdentity)); | ||
2686 | new_msg_ctx.peer = my_identity; | ||
2687 | new_msg_ctx.bloom = NULL; | ||
2688 | new_msg_ctx.hop_count = 0; | ||
2689 | /* Make result routing a higher priority */ | ||
2690 | new_msg_ctx.importance = DHT_DEFAULT_P2P_IMPORTANCE + 2; | ||
2691 | new_msg_ctx.timeout = DHT_DEFAULT_P2P_TIMEOUT; | ||
2692 | new_msg_ctx.unique_id = pos->uid; | ||
2693 | send_reply_to_client(pos->client, &get_result->header, &new_msg_ctx); | ||
2694 | GNUNET_free (get_result); | ||
2695 | pos = pos->next; | ||
2696 | } | ||
2697 | } | ||
2698 | |||
2699 | if (msg_ctx->closest != GNUNET_YES) | ||
2700 | { | ||
2701 | route_message (msg, msg_ctx); | ||
2702 | return; | ||
2703 | } | ||
2704 | |||
2705 | #if DEBUG_DHT | ||
2706 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2707 | "`%s:%s': Received `%s' request (inserting data!), message type %d, key %s, uid %llu\n", | ||
2708 | my_short_id, "DHT", "PUT", put_type, GNUNET_h2s (&msg_ctx->key), | ||
2709 | msg_ctx->unique_id); | ||
2710 | #endif | ||
2711 | |||
2712 | #if DEBUG_DHT_ROUTING | ||
2713 | if ((debug_routes_extended) && (dhtlog_handle != NULL)) | ||
2714 | { | ||
2715 | dhtlog_handle->insert_route (NULL, msg_ctx->unique_id, DHTLOG_ROUTE, | ||
2716 | msg_ctx->hop_count, GNUNET_YES, &my_identity, | ||
2717 | &msg_ctx->key, &msg_ctx->peer, NULL); | ||
2718 | } | ||
2719 | |||
2720 | if ((debug_routes) && (dhtlog_handle != NULL)) | ||
2721 | { | ||
2722 | dhtlog_handle->insert_query (NULL, msg_ctx->unique_id, DHTLOG_PUT, | ||
2723 | msg_ctx->hop_count, GNUNET_YES, &my_identity, | ||
2724 | &msg_ctx->key); | ||
2725 | } | ||
2726 | #endif | ||
2727 | |||
2728 | increment_stats (STAT_PUTS_INSERTED); | ||
2729 | if (datacache != NULL) | ||
2730 | { | ||
2731 | /* Put size is actual data size plus struct overhead plus path length (if any) */ | ||
2732 | put_size = | ||
2733 | data_size + sizeof (struct DHTPutEntry) + | ||
2734 | (msg_ctx->path_history_len * sizeof (struct GNUNET_PeerIdentity)); | ||
2735 | put_entry = GNUNET_malloc (put_size); | ||
2736 | put_entry->data_size = data_size; | ||
2737 | put_entry->path_length = msg_ctx->path_history_len; | ||
2738 | /* Copy data to end of put entry */ | ||
2739 | memcpy (&put_entry[1], &put_msg[1], data_size); | ||
2740 | if (msg_ctx->path_history_len > 0) | ||
2741 | { | ||
2742 | /* Copy path after data */ | ||
2743 | path_offset = (char *) &put_entry[1]; | ||
2744 | path_offset += data_size; | ||
2745 | memcpy (path_offset, msg_ctx->path_history, | ||
2746 | msg_ctx->path_history_len * sizeof (struct GNUNET_PeerIdentity)); | ||
2747 | } | ||
2748 | |||
2749 | ret = | ||
2750 | GNUNET_DATACACHE_put (datacache, &msg_ctx->key, put_size, | ||
2751 | (const char *) put_entry, put_type, | ||
2752 | GNUNET_TIME_absolute_ntoh (put_msg->expiration)); | ||
2753 | GNUNET_free (put_entry); | ||
2754 | } | ||
2755 | else | ||
2756 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2757 | "`%s:%s': %s request received, but have no datacache!\n", | ||
2758 | my_short_id, "DHT", "PUT"); | ||
2759 | |||
2760 | if (stop_on_closest == GNUNET_NO) | ||
2761 | route_message (msg, msg_ctx); | ||
2762 | } | ||
2763 | |||
2764 | |||
2765 | /** | ||
2766 | * To how many peers should we (on average) | ||
2767 | * forward the request to obtain the desired | ||
2768 | * target_replication count (on average). | ||
2769 | * | ||
2770 | * returns: target_replication / (est. hops) + (target_replication * hop_count) | ||
2771 | * where est. hops is typically 2 * the routing table depth | ||
2772 | * | ||
2773 | * @param hop_count number of hops the message has traversed | ||
2774 | * @param target_replication the number of total paths desired | ||
2775 | * | ||
2776 | * @return Some number of peers to forward the message to | ||
2777 | */ | ||
2778 | static unsigned int | ||
2779 | get_forward_count (unsigned int hop_count, size_t target_replication) | ||
2780 | { | ||
2781 | uint32_t random_value; | ||
2782 | unsigned int forward_count; | ||
2783 | float target_value; | ||
2784 | |||
2785 | /** | ||
2786 | * If we are behaving in strict kademlia mode, send multiple initial requests, | ||
2787 | * but then only send to 1 or 0 peers based strictly on the number of hops. | ||
2788 | */ | ||
2789 | if (strict_kademlia == GNUNET_YES) | ||
2790 | { | ||
2791 | if (hop_count == 0) | ||
2792 | return kademlia_replication; | ||
2793 | if (hop_count < log_of_network_size_estimate * 2.0) | ||
2794 | return 1; | ||
2795 | return 0; | ||
2796 | } | ||
2797 | |||
2798 | if (hop_count > log_of_network_size_estimate * 2.0) | ||
2799 | { | ||
2800 | if (GNUNET_YES == paper_forwarding) | ||
2801 | { | ||
2802 | /* Once we have reached our ideal number of hops, don't stop forwarding! */ | ||
2803 | return 1; | ||
2804 | } | ||
2805 | #if DEBUG_DHT | ||
2806 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2807 | "Hop count too high (est %f, lowest %d), NOT Forwarding request\n", | ||
2808 | log_of_network_size_estimate * 2.0, lowest_bucket); | ||
2809 | #endif | ||
2810 | return 0; | ||
2811 | } | ||
2812 | |||
2813 | if (GNUNET_YES == paper_forwarding) | ||
2814 | { | ||
2815 | /* FIXME: re-run replication trials with this formula */ | ||
2816 | target_value = | ||
2817 | 1 + (target_replication - 1.0) / (log_of_network_size_estimate + | ||
2818 | ((float) (target_replication - 1.0) * | ||
2819 | hop_count)); | ||
2820 | /* Set forward count to floor of target_value */ | ||
2821 | forward_count = (unsigned int) target_value; | ||
2822 | /* Subtract forward_count (floor) from target_value (yields value between 0 and 1) */ | ||
2823 | target_value = target_value - forward_count; | ||
2824 | random_value = | ||
2825 | GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, UINT32_MAX); | ||
2826 | |||
2827 | if (random_value < (target_value * UINT32_MAX)) | ||
2828 | forward_count += 1; | ||
2829 | } | ||
2830 | else | ||
2831 | { | ||
2832 | random_value = 0; | ||
2833 | forward_count = 1; | ||
2834 | target_value = | ||
2835 | target_replication / (log_of_network_size_estimate + | ||
2836 | ((float) target_replication * hop_count)); | ||
2837 | if (target_value > 1) | ||
2838 | { | ||
2839 | /* Set forward count to floor of target_value */ | ||
2840 | forward_count = (unsigned int) target_value; | ||
2841 | /* Subtract forward_count (floor) from target_value (yields value between 0 and 1) */ | ||
2842 | target_value = target_value - forward_count; | ||
2843 | } | ||
2844 | else | ||
2845 | random_value = | ||
2846 | GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, UINT32_MAX); | ||
2847 | |||
2848 | if (random_value < (target_value * UINT32_MAX)) | ||
2849 | forward_count += 1; | ||
2850 | } | ||
2851 | |||
2852 | return forward_count; | ||
2853 | } | ||
2854 | |||
2855 | |||
2856 | /** | ||
2857 | * Check whether my identity is closer than any known peers. | ||
2858 | * If a non-null bloomfilter is given, check if this is the closest | ||
2859 | * peer that hasn't already been routed to. | ||
2860 | * | ||
2861 | * @param target hash code to check closeness to | ||
2862 | * @param bloom bloomfilter, exclude these entries from the decision | ||
2863 | * @return GNUNET_YES if node location is closest, | ||
2864 | * GNUNET_NO otherwise. | ||
2865 | */ | ||
2866 | static int | ||
2867 | am_closest_peer (const GNUNET_HashCode * target, | ||
2868 | struct GNUNET_CONTAINER_BloomFilter *bloom) | ||
2869 | { | ||
2870 | int bits; | ||
2871 | int other_bits; | ||
2872 | int bucket_num; | ||
2873 | int count; | ||
2874 | struct PeerInfo *pos; | ||
2875 | unsigned int my_distance; | ||
2876 | |||
2877 | if (0 == memcmp (&my_identity.hashPubKey, target, sizeof (GNUNET_HashCode))) | ||
2878 | return GNUNET_YES; | ||
2879 | |||
2880 | bucket_num = find_current_bucket (target); | ||
2881 | |||
2882 | bits = GNUNET_CRYPTO_hash_matching_bits (&my_identity.hashPubKey, target); | ||
2883 | my_distance = distance (&my_identity.hashPubKey, target); | ||
2884 | pos = k_buckets[bucket_num].head; | ||
2885 | count = 0; | ||
2886 | while ((pos != NULL) && (count < bucket_size)) | ||
2887 | { | ||
2888 | if ((bloom != NULL) && | ||
2889 | (GNUNET_YES == | ||
2890 | GNUNET_CONTAINER_bloomfilter_test (bloom, &pos->id.hashPubKey))) | ||
2891 | { | ||
2892 | pos = pos->next; | ||
2893 | continue; /* Skip already checked entries */ | ||
2894 | } | ||
2895 | |||
2896 | other_bits = GNUNET_CRYPTO_hash_matching_bits (&pos->id.hashPubKey, target); | ||
2897 | if (other_bits > bits) | ||
2898 | return GNUNET_NO; | ||
2899 | else if (other_bits == bits) /* We match the same number of bits */ | ||
2900 | { | ||
2901 | if (strict_kademlia != GNUNET_YES) /* Return that we at as close as any other peer */ | ||
2902 | return GNUNET_YES; | ||
2903 | if (distance (&pos->id.hashPubKey, target) < my_distance) /* Check all known peers, only return if we are the true closest */ | ||
2904 | return GNUNET_NO; | ||
2905 | } | ||
2906 | pos = pos->next; | ||
2907 | } | ||
2908 | |||
2909 | /* No peers closer, we are the closest! */ | ||
2910 | return GNUNET_YES; | ||
2911 | } | ||
2912 | |||
2913 | |||
2914 | /** | ||
2915 | * Select a peer from the routing table that would be a good routing | ||
2916 | * destination for sending a message for "target". The resulting peer | ||
2917 | * must not be in the set of blocked peers.<p> | ||
2918 | * | ||
2919 | * Note that we should not ALWAYS select the closest peer to the | ||
2920 | * target, peers further away from the target should be chosen with | ||
2921 | * exponentially declining probability. | ||
2922 | * | ||
2923 | * @param target the key we are selecting a peer to route to | ||
2924 | * @param bloom a bloomfilter containing entries this request has seen already | ||
2925 | * @param hops how many hops has this message traversed thus far | ||
2926 | * | ||
2927 | * @return Peer to route to, or NULL on error | ||
2928 | */ | ||
2929 | static struct PeerInfo * | ||
2930 | select_peer (const GNUNET_HashCode * target, | ||
2931 | struct GNUNET_CONTAINER_BloomFilter *bloom, unsigned int hops) | ||
2932 | { | ||
2933 | unsigned int bc; | ||
2934 | unsigned int count; | ||
2935 | unsigned int selected; | ||
2936 | struct PeerInfo *pos; | ||
2937 | unsigned int distance; | ||
2938 | unsigned int largest_distance; | ||
2939 | struct PeerInfo *chosen; | ||
2940 | |||
2941 | /** If we are doing kademlia routing (saves some cycles) */ | ||
2942 | if ((strict_kademlia == GNUNET_YES) || (hops >= log_of_network_size_estimate)) | ||
2943 | { | ||
2944 | /* greedy selection (closest peer that is not in bloomfilter) */ | ||
2945 | largest_distance = 0; | ||
2946 | chosen = NULL; | ||
2947 | for (bc = lowest_bucket; bc < MAX_BUCKETS; bc++) | ||
2948 | { | ||
2949 | pos = k_buckets[bc].head; | ||
2950 | count = 0; | ||
2951 | while ((pos != NULL) && (count < bucket_size)) | ||
2952 | { | ||
2953 | /* If we are doing strict Kademlia routing, then checking the bloomfilter is basically cheating! */ | ||
2954 | if (GNUNET_NO == | ||
2955 | GNUNET_CONTAINER_bloomfilter_test (bloom, &pos->id.hashPubKey)) | ||
2956 | { | ||
2957 | distance = inverse_distance (target, &pos->id.hashPubKey); | ||
2958 | if (distance > largest_distance) | ||
2959 | { | ||
2960 | chosen = pos; | ||
2961 | largest_distance = distance; | ||
2962 | } | ||
2963 | } | ||
2964 | count++; | ||
2965 | pos = pos->next; | ||
2966 | } | ||
2967 | } | ||
2968 | if ((largest_distance > 0) && (chosen != NULL)) | ||
2969 | { | ||
2970 | GNUNET_CONTAINER_bloomfilter_add (bloom, &chosen->id.hashPubKey); | ||
2971 | return chosen; | ||
2972 | } | ||
2973 | return NULL; /* no peer available or we are the closest */ | ||
2974 | } | ||
2975 | |||
2976 | |||
2977 | /* select "random" peer */ | ||
2978 | /* count number of peers that are available and not filtered */ | ||
2979 | count = 0; | ||
2980 | for (bc = lowest_bucket; bc < MAX_BUCKETS; bc++) | ||
2981 | { | ||
2982 | pos = k_buckets[bc].head; | ||
2983 | while ((pos != NULL) && (count < bucket_size)) | ||
2984 | { | ||
2985 | if (GNUNET_YES == | ||
2986 | GNUNET_CONTAINER_bloomfilter_test (bloom, &pos->id.hashPubKey)) | ||
2987 | { | ||
2988 | pos = pos->next; | ||
2989 | increment_stats ("# peer blocked from selection by Bloom filter"); | ||
2990 | continue; /* Ignore bloomfiltered peers */ | ||
2991 | } | ||
2992 | count++; | ||
2993 | pos = pos->next; | ||
2994 | } | ||
2995 | } | ||
2996 | if (count == 0) /* No peers to select from! */ | ||
2997 | { | ||
2998 | increment_stats ("# failed to select peer"); | ||
2999 | return NULL; | ||
3000 | } | ||
3001 | /* Now actually choose a peer */ | ||
3002 | selected = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, count); | ||
3003 | count = 0; | ||
3004 | for (bc = lowest_bucket; bc < MAX_BUCKETS; bc++) | ||
3005 | { | ||
3006 | pos = k_buckets[bc].head; | ||
3007 | while ((pos != NULL) && (count < bucket_size)) | ||
3008 | { | ||
3009 | if (GNUNET_YES == | ||
3010 | GNUNET_CONTAINER_bloomfilter_test (bloom, &pos->id.hashPubKey)) | ||
3011 | { | ||
3012 | pos = pos->next; | ||
3013 | continue; /* Ignore bloomfiltered peers */ | ||
3014 | } | ||
3015 | if (0 == selected--) | ||
3016 | return pos; | ||
3017 | pos = pos->next; | ||
3018 | } | ||
3019 | } | ||
3020 | GNUNET_break (0); | ||
3021 | return NULL; | ||
3022 | } | ||
3023 | |||
3024 | |||
3025 | /** | ||
3026 | * Task used to remove recent entries, either | ||
3027 | * after timeout, when full, or on shutdown. | ||
3028 | * | ||
3029 | * @param cls the entry to remove | ||
3030 | * @param tc context, reason, etc. | ||
3031 | */ | ||
3032 | static void | ||
3033 | remove_recent (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
3034 | { | ||
3035 | struct RecentRequest *req = cls; | ||
3036 | static GNUNET_HashCode hash; | ||
3037 | |||
3038 | GNUNET_assert (req != NULL); | ||
3039 | hash_from_uid (req->uid, &hash); | ||
3040 | #if HAVE_UID_FOR_TESTING > 1 | ||
3041 | GNUNET_assert (GNUNET_YES == | ||
3042 | GNUNET_CONTAINER_multihashmap_remove (recent.hashmap, &hash, | ||
3043 | req)); | ||
3044 | #endif | ||
3045 | GNUNET_CONTAINER_heap_remove_node (req->heap_node); | ||
3046 | GNUNET_CONTAINER_bloomfilter_free (req->bloom); | ||
3047 | GNUNET_free (req); | ||
3048 | |||
3049 | /* | ||
3050 | * if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) && (0 == GNUNET_CONTAINER_multihashmap_size(recent.hashmap)) && (0 == GNUNET_CONTAINER_heap_get_size(recent.minHeap))) | ||
3051 | * { | ||
3052 | * GNUNET_CONTAINER_multihashmap_destroy(recent.hashmap); | ||
3053 | * GNUNET_CONTAINER_heap_destroy(recent.minHeap); | ||
3054 | * } | ||
3055 | */ | ||
3056 | } | ||
3057 | |||
3058 | /** | ||
3059 | * Remember this routing request so that if a reply is | ||
3060 | * received we can either forward it to the correct peer | ||
3061 | * or return the result locally. | ||
3062 | * | ||
3063 | * @param msg_ctx Context of the route request | ||
3064 | * | ||
3065 | * @return GNUNET_YES if this response was cached, GNUNET_NO if not | ||
3066 | */ | ||
3067 | static int | ||
3068 | cache_response (struct DHT_MessageContext *msg_ctx) | ||
3069 | { | ||
3070 | struct DHTQueryRecord *record; | ||
3071 | struct DHTRouteSource *source_info; | ||
3072 | struct DHTRouteSource *pos; | ||
3073 | struct GNUNET_TIME_Absolute now; | ||
3074 | unsigned int current_size; | ||
3075 | |||
3076 | current_size = GNUNET_CONTAINER_multihashmap_size (forward_list.hashmap); | ||
3077 | |||
3078 | #if DELETE_WHEN_FULL | ||
3079 | while (current_size >= MAX_OUTSTANDING_FORWARDS) | ||
3080 | { | ||
3081 | source_info = GNUNET_CONTAINER_heap_remove_root (forward_list.minHeap); | ||
3082 | GNUNET_assert (source_info != NULL); | ||
3083 | record = source_info->record; | ||
3084 | GNUNET_CONTAINER_DLL_remove (record->head, record->tail, source_info); | ||
3085 | if (record->head == NULL) /* No more entries in DLL */ | ||
3086 | { | ||
3087 | GNUNET_assert (GNUNET_YES == | ||
3088 | GNUNET_CONTAINER_multihashmap_remove (forward_list.hashmap, | ||
3089 | &record->key, | ||
3090 | record)); | ||
3091 | GNUNET_free (record); | ||
3092 | } | ||
3093 | if (source_info->delete_task != GNUNET_SCHEDULER_NO_TASK) | ||
3094 | { | ||
3095 | GNUNET_SCHEDULER_cancel (source_info->delete_task); | ||
3096 | source_info->delete_task = GNUNET_SCHEDULER_NO_TASK; | ||
3097 | } | ||
3098 | if (source_info->find_peers_responded != NULL) | ||
3099 | GNUNET_CONTAINER_bloomfilter_free (source_info->find_peers_responded); | ||
3100 | GNUNET_free (source_info); | ||
3101 | current_size = GNUNET_CONTAINER_multihashmap_size (forward_list.hashmap); | ||
3102 | } | ||
3103 | #endif | ||
3104 | /** Non-local request and have too many outstanding forwards, discard! */ | ||
3105 | if ((current_size >= MAX_OUTSTANDING_FORWARDS) && (msg_ctx->client == NULL)) | ||
3106 | return GNUNET_NO; | ||
3107 | |||
3108 | now = GNUNET_TIME_absolute_get (); | ||
3109 | record = | ||
3110 | GNUNET_CONTAINER_multihashmap_get (forward_list.hashmap, &msg_ctx->key); | ||
3111 | if (record != NULL) /* Already know this request! */ | ||
3112 | { | ||
3113 | pos = record->head; | ||
3114 | while (pos != NULL) | ||
3115 | { | ||
3116 | if (0 == | ||
3117 | memcmp (&msg_ctx->peer, &pos->source, | ||
3118 | sizeof (struct GNUNET_PeerIdentity))) | ||
3119 | break; /* Already have this peer in reply list! */ | ||
3120 | pos = pos->next; | ||
3121 | } | ||
3122 | if ((pos != NULL) && (pos->client == msg_ctx->client)) /* Seen this already */ | ||
3123 | { | ||
3124 | GNUNET_CONTAINER_heap_update_cost (forward_list.minHeap, pos->hnode, | ||
3125 | now.abs_value); | ||
3126 | return GNUNET_NO; | ||
3127 | } | ||
3128 | } | ||
3129 | else | ||
3130 | { | ||
3131 | record = GNUNET_malloc (sizeof (struct DHTQueryRecord)); | ||
3132 | GNUNET_assert (GNUNET_OK == | ||
3133 | GNUNET_CONTAINER_multihashmap_put (forward_list.hashmap, | ||
3134 | &msg_ctx->key, record, | ||
3135 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
3136 | memcpy (&record->key, &msg_ctx->key, sizeof (GNUNET_HashCode)); | ||
3137 | } | ||
3138 | |||
3139 | source_info = GNUNET_malloc (sizeof (struct DHTRouteSource)); | ||
3140 | source_info->record = record; | ||
3141 | source_info->delete_task = | ||
3142 | GNUNET_SCHEDULER_add_delayed (DHT_FORWARD_TIMEOUT, &remove_forward_entry, | ||
3143 | source_info); | ||
3144 | source_info->find_peers_responded = | ||
3145 | GNUNET_CONTAINER_bloomfilter_init (NULL, DHT_BLOOM_SIZE, DHT_BLOOM_K); | ||
3146 | source_info->source = msg_ctx->peer; | ||
3147 | GNUNET_CONTAINER_DLL_insert_after (record->head, record->tail, record->tail, | ||
3148 | source_info); | ||
3149 | if (msg_ctx->client != NULL) /* For local request, set timeout so high it effectively never gets pushed out */ | ||
3150 | { | ||
3151 | source_info->client = msg_ctx->client; | ||
3152 | now = GNUNET_TIME_absolute_get_forever (); | ||
3153 | } | ||
3154 | source_info->hnode = | ||
3155 | GNUNET_CONTAINER_heap_insert (forward_list.minHeap, source_info, | ||
3156 | now.abs_value); | ||
3157 | source_info->uid = msg_ctx->unique_id; | ||
3158 | #if DEBUG_DHT > 1 | ||
3159 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3160 | "`%s:%s': Created new forward source info for %s uid %llu\n", | ||
3161 | my_short_id, "DHT", GNUNET_h2s (&msg_ctx->key), | ||
3162 | msg_ctx->unique_id); | ||
3163 | #endif | ||
3164 | return GNUNET_YES; | ||
3165 | } | ||
3166 | |||
3167 | |||
3168 | /** | ||
3169 | * Main function that handles whether or not to route a message to other | ||
3170 | * peers. | ||
3171 | * | ||
3172 | * @param msg the message to be routed | ||
3173 | * @param msg_ctx the context containing all pertinent information about the message | ||
3174 | */ | ||
3175 | static void | ||
3176 | route_message (const struct GNUNET_MessageHeader *msg, | ||
3177 | struct DHT_MessageContext *msg_ctx) | ||
3178 | { | ||
3179 | int i; | ||
3180 | struct PeerInfo *selected; | ||
3181 | |||
3182 | #if DEBUG_DHT_ROUTING > 1 | ||
3183 | struct PeerInfo *nearest; | ||
3184 | #endif | ||
3185 | unsigned int target_forward_count; | ||
3186 | unsigned int forward_count; | ||
3187 | struct RecentRequest *recent_req; | ||
3188 | #if HAVE_UID_FOR_TESTING > 1 | ||
3189 | GNUNET_HashCode unique_hash; | ||
3190 | #endif | ||
3191 | char *stat_forward_count; | ||
3192 | char *temp_stat_str; | ||
3193 | |||
3194 | #if DEBUG_DHT_ROUTING | ||
3195 | int ret; | ||
3196 | #endif | ||
3197 | |||
3198 | if (malicious_dropper == GNUNET_YES) | ||
3199 | { | ||
3200 | #if DEBUG_DHT_ROUTING | ||
3201 | if ((debug_routes_extended) && (dhtlog_handle != NULL)) | ||
3202 | { | ||
3203 | dhtlog_handle->insert_route (NULL, msg_ctx->unique_id, DHTLOG_ROUTE, | ||
3204 | msg_ctx->hop_count, GNUNET_SYSERR, | ||
3205 | &my_identity, &msg_ctx->key, &msg_ctx->peer, | ||
3206 | NULL); | ||
3207 | } | ||
3208 | #endif | ||
3209 | if (msg_ctx->bloom != NULL) | ||
3210 | { | ||
3211 | GNUNET_CONTAINER_bloomfilter_free (msg_ctx->bloom); | ||
3212 | msg_ctx->bloom = NULL; | ||
3213 | } | ||
3214 | return; | ||
3215 | } | ||
3216 | |||
3217 | increment_stats (STAT_ROUTES); | ||
3218 | target_forward_count = | ||
3219 | get_forward_count (msg_ctx->hop_count, msg_ctx->replication); | ||
3220 | GNUNET_asprintf (&stat_forward_count, "# forward counts of %d", | ||
3221 | target_forward_count); | ||
3222 | increment_stats (stat_forward_count); | ||
3223 | GNUNET_free (stat_forward_count); | ||
3224 | if (msg_ctx->bloom == NULL) | ||
3225 | msg_ctx->bloom = | ||
3226 | GNUNET_CONTAINER_bloomfilter_init (NULL, DHT_BLOOM_SIZE, DHT_BLOOM_K); | ||
3227 | |||
3228 | if ((stop_on_closest == GNUNET_YES) && (msg_ctx->closest == GNUNET_YES) && | ||
3229 | (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_DHT_PUT)) | ||
3230 | target_forward_count = 0; | ||
3231 | |||
3232 | /** | ||
3233 | * NOTICE: In Kademlia, a find peer request goes no further if the peer doesn't return | ||
3234 | * any closer peers (which is being checked for below). Since we are doing recursive | ||
3235 | * routing we have no choice but to stop forwarding in this case. This means that at | ||
3236 | * any given step the request may NOT be forwarded to alpha peers (because routes will | ||
3237 | * stop and the parallel route will not be aware of it). Of course, assuming that we | ||
3238 | * have fulfilled the Kademlia requirements for routing table fullness this will never | ||
3239 | * ever ever be a problem. | ||
3240 | * | ||
3241 | * However, is this fair? | ||
3242 | * | ||
3243 | * Since we use these requests to build our routing tables (and we build them in the | ||
3244 | * testing driver) we will ignore this restriction for FIND_PEER messages so that | ||
3245 | * routing tables still get constructed. | ||
3246 | */ | ||
3247 | if ((GNUNET_YES == strict_kademlia) && (msg_ctx->closest == GNUNET_YES) && | ||
3248 | (msg_ctx->hop_count > 0) && | ||
3249 | (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_DHT_FIND_PEER)) | ||
3250 | target_forward_count = 0; | ||
3251 | |||
3252 | #if HAVE_UID_FOR_TESTING > 1 | ||
3253 | /* BUG HERE: recent uses unique_id! So if all unique-IDs are 0, we get | ||
3254 | easily into trouble!!! Also, this should not even be necessary... */ | ||
3255 | hash_from_uid (msg_ctx->unique_id, &unique_hash); | ||
3256 | if (GNUNET_YES == | ||
3257 | GNUNET_CONTAINER_multihashmap_contains (recent.hashmap, &unique_hash)) | ||
3258 | { | ||
3259 | recent_req = | ||
3260 | GNUNET_CONTAINER_multihashmap_get (recent.hashmap, &unique_hash); | ||
3261 | GNUNET_assert (recent_req != NULL); | ||
3262 | if (0 != memcmp (&recent_req->key, &msg_ctx->key, sizeof (GNUNET_HashCode))) | ||
3263 | increment_stats (STAT_DUPLICATE_UID); | ||
3264 | else | ||
3265 | { | ||
3266 | increment_stats (STAT_RECENT_SEEN); | ||
3267 | GNUNET_CONTAINER_bloomfilter_or2 (msg_ctx->bloom, recent_req->bloom, | ||
3268 | DHT_BLOOM_SIZE); | ||
3269 | } | ||
3270 | } | ||
3271 | else | ||
3272 | #endif | ||
3273 | { | ||
3274 | recent_req = GNUNET_malloc (sizeof (struct RecentRequest)); | ||
3275 | recent_req->uid = msg_ctx->unique_id; | ||
3276 | memcpy (&recent_req->key, &msg_ctx->key, sizeof (GNUNET_HashCode)); | ||
3277 | recent_req->remove_task = | ||
3278 | GNUNET_SCHEDULER_add_delayed (DEFAULT_RECENT_REMOVAL, &remove_recent, | ||
3279 | recent_req); | ||
3280 | recent_req->heap_node = | ||
3281 | GNUNET_CONTAINER_heap_insert (recent.minHeap, recent_req, | ||
3282 | GNUNET_TIME_absolute_get ().abs_value); | ||
3283 | recent_req->bloom = | ||
3284 | GNUNET_CONTAINER_bloomfilter_init (NULL, DHT_BLOOM_SIZE, DHT_BLOOM_K); | ||
3285 | #if HAVE_UID_FOR_TESTING > 1 | ||
3286 | GNUNET_CONTAINER_multihashmap_put (recent.hashmap, &unique_hash, recent_req, | ||
3287 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | ||
3288 | #endif | ||
3289 | } | ||
3290 | |||
3291 | if (GNUNET_CONTAINER_heap_get_size (recent.minHeap) > DHT_MAX_RECENT) | ||
3292 | { | ||
3293 | recent_req = GNUNET_CONTAINER_heap_peek (recent.minHeap); | ||
3294 | GNUNET_assert (recent_req != NULL); | ||
3295 | GNUNET_SCHEDULER_cancel (recent_req->remove_task); | ||
3296 | recent_req->remove_task = | ||
3297 | GNUNET_SCHEDULER_add_now (&remove_recent, recent_req); | ||
3298 | } | ||
3299 | |||
3300 | forward_count = 0; | ||
3301 | for (i = 0; i < target_forward_count; i++) | ||
3302 | { | ||
3303 | selected = select_peer (&msg_ctx->key, msg_ctx->bloom, msg_ctx->hop_count); | ||
3304 | if (selected == NULL) | ||
3305 | break; | ||
3306 | forward_count++; | ||
3307 | if (GNUNET_CRYPTO_hash_matching_bits | ||
3308 | (&selected->id.hashPubKey, | ||
3309 | &msg_ctx->key) >= | ||
3310 | GNUNET_CRYPTO_hash_matching_bits (&my_identity.hashPubKey, | ||
3311 | &msg_ctx->key)) | ||
3312 | GNUNET_asprintf (&temp_stat_str, | ||
3313 | "# requests routed to close(r) peer hop %u", | ||
3314 | msg_ctx->hop_count); | ||
3315 | else | ||
3316 | GNUNET_asprintf (&temp_stat_str, | ||
3317 | "# requests routed to less close peer hop %u", | ||
3318 | msg_ctx->hop_count); | ||
3319 | if (temp_stat_str != NULL) | ||
3320 | { | ||
3321 | increment_stats (temp_stat_str); | ||
3322 | GNUNET_free (temp_stat_str); | ||
3323 | } | ||
3324 | GNUNET_CONTAINER_bloomfilter_add (msg_ctx->bloom, | ||
3325 | &selected->id.hashPubKey); | ||
3326 | #if DEBUG_DHT_ROUTING > 1 | ||
3327 | nearest = find_closest_peer (&msg_ctx->key); | ||
3328 | nearest_buf = GNUNET_strdup (GNUNET_i2s (&nearest->id)); | ||
3329 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3330 | "`%s:%s': Forwarding request key %s uid %llu to peer %s (closest %s, bits %d, distance %u)\n", | ||
3331 | my_short_id, "DHT", GNUNET_h2s (&msg_ctx->key), | ||
3332 | msg_ctx->unique_id, GNUNET_i2s (&selected->id), nearest_buf, | ||
3333 | GNUNET_CRYPTO_hash_matching_bits (&nearest->id.hashPubKey, | ||
3334 | msg_ctx->key), | ||
3335 | distance (&nearest->id.hashPubKey, msg_ctx->key)); | ||
3336 | GNUNET_free (nearest_buf); | ||
3337 | #endif | ||
3338 | #if DEBUG_DHT_ROUTING | ||
3339 | if ((debug_routes_extended) && (dhtlog_handle != NULL)) | ||
3340 | { | ||
3341 | dhtlog_handle->insert_route (NULL, msg_ctx->unique_id, DHTLOG_ROUTE, | ||
3342 | msg_ctx->hop_count, GNUNET_NO, | ||
3343 | &my_identity, &msg_ctx->key, &msg_ctx->peer, | ||
3344 | &selected->id); | ||
3345 | } | ||
3346 | #endif | ||
3347 | forward_message (msg, selected, msg_ctx); | ||
3348 | } | ||
3349 | |||
3350 | if (msg_ctx->bloom != NULL) | ||
3351 | { | ||
3352 | GNUNET_CONTAINER_bloomfilter_or2 (recent_req->bloom, msg_ctx->bloom, | ||
3353 | DHT_BLOOM_SIZE); | ||
3354 | GNUNET_CONTAINER_bloomfilter_free (msg_ctx->bloom); | ||
3355 | msg_ctx->bloom = NULL; | ||
3356 | } | ||
3357 | |||
3358 | #if DEBUG_DHT_ROUTING | ||
3359 | if (forward_count == 0) | ||
3360 | ret = GNUNET_SYSERR; | ||
3361 | else | ||
3362 | ret = GNUNET_NO; | ||
3363 | |||
3364 | if ((debug_routes_extended) && (dhtlog_handle != NULL)) | ||
3365 | { | ||
3366 | dhtlog_handle->insert_route (NULL, msg_ctx->unique_id, DHTLOG_ROUTE, | ||
3367 | msg_ctx->hop_count, ret, &my_identity, | ||
3368 | &msg_ctx->key, &msg_ctx->peer, NULL); | ||
3369 | } | ||
3370 | #endif | ||
3371 | } | ||
3372 | |||
3373 | |||
3374 | /** | ||
3375 | * Main function that handles whether or not to route a message to other | ||
3376 | * peers. | ||
3377 | * | ||
3378 | * @param msg the message to be routed | ||
3379 | * @param msg_ctx the context containing all pertinent information about the message | ||
3380 | */ | ||
3381 | static void | ||
3382 | demultiplex_message (const struct GNUNET_MessageHeader *msg, | ||
3383 | struct DHT_MessageContext *msg_ctx) | ||
3384 | { | ||
3385 | /* FIXME: Should we use closest excluding those we won't route to (the bloomfilter problem)? */ | ||
3386 | msg_ctx->closest = am_closest_peer (&msg_ctx->key, msg_ctx->bloom); | ||
3387 | |||
3388 | switch (ntohs (msg->type)) | ||
3389 | { | ||
3390 | case GNUNET_MESSAGE_TYPE_DHT_GET: /* Add to hashmap of requests seen, search for data (always) */ | ||
3391 | cache_response (msg_ctx); | ||
3392 | handle_dht_get (msg, msg_ctx); | ||
3393 | break; | ||
3394 | case GNUNET_MESSAGE_TYPE_DHT_PUT: /* Check if closest, if so insert data. */ | ||
3395 | increment_stats (STAT_PUTS); | ||
3396 | handle_dht_put (msg, msg_ctx); | ||
3397 | break; | ||
3398 | case GNUNET_MESSAGE_TYPE_DHT_FIND_PEER: /* Check if closest and not started by us, check options, add to requests seen */ | ||
3399 | increment_stats (STAT_FIND_PEER); | ||
3400 | if (((msg_ctx->hop_count > 0) && | ||
3401 | (0 != | ||
3402 | memcmp (&msg_ctx->peer, &my_identity, | ||
3403 | sizeof (struct GNUNET_PeerIdentity)))) || | ||
3404 | (msg_ctx->client != NULL)) | ||
3405 | { | ||
3406 | cache_response (msg_ctx); | ||
3407 | if ((msg_ctx->closest == GNUNET_YES) || | ||
3408 | (msg_ctx->msg_options == GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE)) | ||
3409 | handle_dht_find_peer (msg, msg_ctx); | ||
3410 | } | ||
3411 | else | ||
3412 | route_message (msg, msg_ctx); | ||
3413 | #if DEBUG_DHT_ROUTING | ||
3414 | if (msg_ctx->hop_count == 0) /* Locally initiated request */ | ||
3415 | { | ||
3416 | if ((debug_routes) && (dhtlog_handle != NULL)) | ||
3417 | { | ||
3418 | dhtlog_handle->insert_dhtkey (NULL, &msg_ctx->key); | ||
3419 | dhtlog_handle->insert_query (NULL, msg_ctx->unique_id, DHTLOG_FIND_PEER, | ||
3420 | msg_ctx->hop_count, GNUNET_NO, | ||
3421 | &my_identity, &msg_ctx->key); | ||
3422 | } | ||
3423 | } | ||
3424 | #endif | ||
3425 | break; | ||
3426 | default: | ||
3427 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
3428 | "`%s': Message type (%d) not handled, forwarding anyway!\n", | ||
3429 | "DHT", ntohs (msg->type)); | ||
3430 | route_message (msg, msg_ctx); | ||
3431 | } | ||
3432 | } | ||
3433 | |||
3434 | |||
3435 | /** | ||
3436 | * Iterator over hash map entries. | ||
3437 | * | ||
3438 | * @param cls client to search for in source routes | ||
3439 | * @param key current key code (ignored) | ||
3440 | * @param value value in the hash map, a DHTQueryRecord | ||
3441 | * @return GNUNET_YES if we should continue to | ||
3442 | * iterate, | ||
3443 | * GNUNET_NO if not. | ||
3444 | */ | ||
3445 | static int | ||
3446 | find_client_records (void *cls, const GNUNET_HashCode * key, void *value) | ||
3447 | { | ||
3448 | struct ClientList *client = cls; | ||
3449 | struct DHTQueryRecord *record = value; | ||
3450 | struct DHTRouteSource *pos; | ||
3451 | |||
3452 | pos = record->head; | ||
3453 | while (pos != NULL) | ||
3454 | { | ||
3455 | if (pos->client == client) | ||
3456 | break; | ||
3457 | pos = pos->next; | ||
3458 | } | ||
3459 | if (pos != NULL) | ||
3460 | { | ||
3461 | GNUNET_CONTAINER_DLL_remove (record->head, record->tail, pos); | ||
3462 | GNUNET_CONTAINER_heap_remove_node (pos->hnode); | ||
3463 | if (pos->delete_task != GNUNET_SCHEDULER_NO_TASK) | ||
3464 | { | ||
3465 | GNUNET_SCHEDULER_cancel (pos->delete_task); | ||
3466 | pos->delete_task = GNUNET_SCHEDULER_NO_TASK; | ||
3467 | } | ||
3468 | if (pos->find_peers_responded != NULL) | ||
3469 | GNUNET_CONTAINER_bloomfilter_free (pos->find_peers_responded); | ||
3470 | GNUNET_free (pos); | ||
3471 | } | ||
3472 | if (record->head == NULL) /* No more entries in DLL */ | ||
3473 | { | ||
3474 | GNUNET_assert (GNUNET_YES == | ||
3475 | GNUNET_CONTAINER_multihashmap_remove (forward_list.hashmap, | ||
3476 | &record->key, record)); | ||
3477 | GNUNET_free (record); | ||
3478 | } | ||
3479 | return GNUNET_YES; | ||
3480 | } | ||
3481 | |||
3482 | /** | ||
3483 | * Functions with this signature are called whenever a client | ||
3484 | * is disconnected on the network level. | ||
3485 | * | ||
3486 | * @param cls closure (NULL for dht) | ||
3487 | * @param client identification of the client; NULL | ||
3488 | * for the last call when the server is destroyed | ||
3489 | */ | ||
3490 | static void | ||
3491 | handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) | ||
3492 | { | ||
3493 | struct ClientList *pos = client_list; | ||
3494 | struct ClientList *prev; | ||
3495 | struct ClientList *found; | ||
3496 | struct PendingMessage *reply; | ||
3497 | |||
3498 | prev = NULL; | ||
3499 | found = NULL; | ||
3500 | while (pos != NULL) | ||
3501 | { | ||
3502 | if (pos->client_handle == client) | ||
3503 | { | ||
3504 | if (prev != NULL) | ||
3505 | prev->next = pos->next; | ||
3506 | else | ||
3507 | client_list = pos->next; | ||
3508 | found = pos; | ||
3509 | break; | ||
3510 | } | ||
3511 | prev = pos; | ||
3512 | pos = pos->next; | ||
3513 | } | ||
3514 | |||
3515 | if (found != NULL) | ||
3516 | { | ||
3517 | if (found->transmit_handle != NULL) | ||
3518 | GNUNET_CONNECTION_notify_transmit_ready_cancel (found->transmit_handle); | ||
3519 | |||
3520 | while (NULL != (reply = found->pending_head)) | ||
3521 | { | ||
3522 | GNUNET_CONTAINER_DLL_remove (found->pending_head, found->pending_tail, | ||
3523 | reply); | ||
3524 | GNUNET_free (reply); | ||
3525 | } | ||
3526 | GNUNET_CONTAINER_multihashmap_iterate (forward_list.hashmap, | ||
3527 | &find_client_records, found); | ||
3528 | GNUNET_free (found); | ||
3529 | } | ||
3530 | } | ||
3531 | |||
3532 | /** | ||
3533 | * Find a client if it exists, add it otherwise. | ||
3534 | * | ||
3535 | * @param client the server handle to the client | ||
3536 | * | ||
3537 | * @return the client if found, a new client otherwise | ||
3538 | */ | ||
3539 | static struct ClientList * | ||
3540 | find_active_client (struct GNUNET_SERVER_Client *client) | ||
3541 | { | ||
3542 | struct ClientList *pos = client_list; | ||
3543 | struct ClientList *ret; | ||
3544 | |||
3545 | while (pos != NULL) | ||
3546 | { | ||
3547 | if (pos->client_handle == client) | ||
3548 | return pos; | ||
3549 | pos = pos->next; | ||
3550 | } | ||
3551 | |||
3552 | ret = GNUNET_malloc (sizeof (struct ClientList)); | ||
3553 | ret->client_handle = client; | ||
3554 | ret->next = client_list; | ||
3555 | client_list = ret; | ||
3556 | |||
3557 | return ret; | ||
3558 | } | ||
3559 | |||
3560 | #if HAVE_MALICIOUS | ||
3561 | /** | ||
3562 | * Task to send a malicious put message across the network. | ||
3563 | * | ||
3564 | * @param cls closure for this task | ||
3565 | * @param tc the context under which the task is running | ||
3566 | */ | ||
3567 | static void | ||
3568 | malicious_put_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
3569 | { | ||
3570 | static struct GNUNET_DHT_PutMessage put_message; | ||
3571 | static struct DHT_MessageContext msg_ctx; | ||
3572 | static GNUNET_HashCode key; | ||
3573 | uint32_t random_key; | ||
3574 | |||
3575 | if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) | ||
3576 | return; | ||
3577 | put_message.header.size = htons (sizeof (struct GNUNET_DHT_PutMessage)); | ||
3578 | put_message.header.type = htons (GNUNET_MESSAGE_TYPE_DHT_PUT); | ||
3579 | put_message.type = htonl (GNUNET_BLOCK_DHT_MALICIOUS_MESSAGE_TYPE); | ||
3580 | put_message.expiration = | ||
3581 | GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_forever ()); | ||
3582 | memset (&msg_ctx, 0, sizeof (struct DHT_MessageContext)); | ||
3583 | random_key = | ||
3584 | GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX); | ||
3585 | GNUNET_CRYPTO_hash (&random_key, sizeof (uint32_t), &key); | ||
3586 | memcpy (&msg_ctx.key, &key, sizeof (GNUNET_HashCode)); | ||
3587 | msg_ctx.unique_id = | ||
3588 | GNUNET_ntohll (GNUNET_CRYPTO_random_u64 | ||
3589 | (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX)); | ||
3590 | msg_ctx.replication = ntohl (DHT_DEFAULT_FIND_PEER_REPLICATION); | ||
3591 | msg_ctx.msg_options = ntohl (0); | ||
3592 | msg_ctx.network_size = log_of_network_size_estimate; | ||
3593 | msg_ctx.peer = my_identity; | ||
3594 | msg_ctx.importance = DHT_DEFAULT_P2P_IMPORTANCE; | ||
3595 | msg_ctx.timeout = DHT_DEFAULT_P2P_TIMEOUT; | ||
3596 | #if DEBUG_DHT_ROUTING | ||
3597 | if (dhtlog_handle != NULL) | ||
3598 | dhtlog_handle->insert_dhtkey (NULL, &key); | ||
3599 | #endif | ||
3600 | increment_stats (STAT_PUT_START); | ||
3601 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3602 | "%s:%s Sending malicious PUT message with hash %s\n", my_short_id, | ||
3603 | "DHT", GNUNET_h2s (&key)); | ||
3604 | demultiplex_message (&put_message.header, &msg_ctx); | ||
3605 | GNUNET_SCHEDULER_add_delayed (malicious_put_frequency, &malicious_put_task, | ||
3606 | NULL); | ||
3607 | } | ||
3608 | |||
3609 | |||
3610 | /** | ||
3611 | * Task to send a malicious put message across the network. | ||
3612 | * | ||
3613 | * @param cls closure for this task | ||
3614 | * @param tc the context under which the task is running | ||
3615 | */ | ||
3616 | static void | ||
3617 | malicious_get_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
3618 | { | ||
3619 | static struct GNUNET_DHT_GetMessage get_message; | ||
3620 | struct DHT_MessageContext msg_ctx; | ||
3621 | static GNUNET_HashCode key; | ||
3622 | uint32_t random_key; | ||
3623 | |||
3624 | if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) | ||
3625 | return; | ||
3626 | |||
3627 | get_message.header.size = htons (sizeof (struct GNUNET_DHT_GetMessage)); | ||
3628 | get_message.header.type = htons (GNUNET_MESSAGE_TYPE_DHT_GET); | ||
3629 | get_message.type = htonl (GNUNET_BLOCK_DHT_MALICIOUS_MESSAGE_TYPE); | ||
3630 | memset (&msg_ctx, 0, sizeof (struct DHT_MessageContext)); | ||
3631 | random_key = | ||
3632 | GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX); | ||
3633 | GNUNET_CRYPTO_hash (&random_key, sizeof (uint32_t), &key); | ||
3634 | memcpy (&msg_ctx.key, &key, sizeof (GNUNET_HashCode)); | ||
3635 | msg_ctx.unique_id = | ||
3636 | GNUNET_ntohll (GNUNET_CRYPTO_random_u64 | ||
3637 | (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX)); | ||
3638 | msg_ctx.replication = ntohl (DHT_DEFAULT_FIND_PEER_REPLICATION); | ||
3639 | msg_ctx.msg_options = ntohl (0); | ||
3640 | msg_ctx.network_size = log_of_network_size_estimate; | ||
3641 | msg_ctx.peer = my_identity; | ||
3642 | msg_ctx.importance = DHT_DEFAULT_P2P_IMPORTANCE; | ||
3643 | msg_ctx.timeout = DHT_DEFAULT_P2P_TIMEOUT; | ||
3644 | #if DEBUG_DHT_ROUTING | ||
3645 | if (dhtlog_handle != NULL) | ||
3646 | dhtlog_handle->insert_dhtkey (NULL, &key); | ||
3647 | #endif | ||
3648 | increment_stats (STAT_GET_START); | ||
3649 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3650 | "%s:%s Sending malicious GET message with hash %s\n", my_short_id, | ||
3651 | "DHT", GNUNET_h2s (&key)); | ||
3652 | demultiplex_message (&get_message.header, &msg_ctx); | ||
3653 | GNUNET_SCHEDULER_add_delayed (malicious_get_frequency, &malicious_get_task, | ||
3654 | NULL); | ||
3655 | } | ||
3656 | #endif | ||
3657 | |||
3658 | |||
3659 | /** | ||
3660 | * Iterator over hash map entries. | ||
3661 | * | ||
3662 | * @param cls closure | ||
3663 | * @param key current key code | ||
3664 | * @param value value in the hash map | ||
3665 | * @return GNUNET_YES if we should continue to | ||
3666 | * iterate, | ||
3667 | * GNUNET_NO if not. | ||
3668 | */ | ||
3669 | static int | ||
3670 | add_known_to_bloom (void *cls, const GNUNET_HashCode * key, void *value) | ||
3671 | { | ||
3672 | struct GNUNET_CONTAINER_BloomFilter *bloom = cls; | ||
3673 | |||
3674 | GNUNET_CONTAINER_bloomfilter_add (bloom, key); | ||
3675 | return GNUNET_YES; | ||
3676 | } | ||
3677 | |||
3678 | /** | ||
3679 | * Task to send a find peer message for our own peer identifier | ||
3680 | * so that we can find the closest peers in the network to ourselves | ||
3681 | * and attempt to connect to them. | ||
3682 | * | ||
3683 | * @param cls closure for this task | ||
3684 | * @param tc the context under which the task is running | ||
3685 | */ | ||
3686 | static void | ||
3687 | send_find_peer_message (void *cls, | ||
3688 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
3689 | { | ||
3690 | struct GNUNET_DHT_FindPeerMessage *find_peer_msg; | ||
3691 | struct DHT_MessageContext msg_ctx; | ||
3692 | struct GNUNET_TIME_Relative next_send_time; | ||
3693 | struct GNUNET_CONTAINER_BloomFilter *temp_bloom; | ||
3694 | |||
3695 | if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) | ||
3696 | return; | ||
3697 | |||
3698 | if ((newly_found_peers > bucket_size) && (GNUNET_YES == do_find_peer)) /* If we are finding peers already, no need to send out our request right now! */ | ||
3699 | { | ||
3700 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
3701 | "Have %d newly found peers since last find peer message sent!\n", | ||
3702 | newly_found_peers); | ||
3703 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, | ||
3704 | &send_find_peer_message, NULL); | ||
3705 | newly_found_peers = 0; | ||
3706 | return; | ||
3707 | } | ||
3708 | |||
3709 | increment_stats (STAT_FIND_PEER_START); | ||
3710 | #if FIND_PEER_WITH_HELLO | ||
3711 | find_peer_msg = | ||
3712 | GNUNET_malloc (sizeof (struct GNUNET_DHT_FindPeerMessage) + | ||
3713 | GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) | ||
3714 | my_hello)); | ||
3715 | find_peer_msg->header.size = | ||
3716 | htons (sizeof (struct GNUNET_DHT_FindPeerMessage) + | ||
3717 | GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) my_hello)); | ||
3718 | memcpy (&find_peer_msg[1], my_hello, | ||
3719 | GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) my_hello)); | ||
3720 | #else | ||
3721 | find_peer_msg = GNUNET_malloc (sizeof (struct GNUNET_DHT_FindPeerMessage)); | ||
3722 | find_peer_msg->header.size = | ||
3723 | htons (sizeof (struct GNUNET_DHT_FindPeerMessage)); | ||
3724 | #endif | ||
3725 | find_peer_msg->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_FIND_PEER); | ||
3726 | temp_bloom = | ||
3727 | GNUNET_CONTAINER_bloomfilter_init (NULL, DHT_BLOOM_SIZE, DHT_BLOOM_K); | ||
3728 | GNUNET_CONTAINER_multihashmap_iterate (all_known_peers, &add_known_to_bloom, | ||
3729 | temp_bloom); | ||
3730 | GNUNET_assert (GNUNET_OK == | ||
3731 | GNUNET_CONTAINER_bloomfilter_get_raw_data (temp_bloom, | ||
3732 | find_peer_msg-> | ||
3733 | bloomfilter, | ||
3734 | DHT_BLOOM_SIZE)); | ||
3735 | GNUNET_CONTAINER_bloomfilter_free (temp_bloom); | ||
3736 | memset (&msg_ctx, 0, sizeof (struct DHT_MessageContext)); | ||
3737 | memcpy (&msg_ctx.key, &my_identity.hashPubKey, sizeof (GNUNET_HashCode)); | ||
3738 | msg_ctx.unique_id = | ||
3739 | GNUNET_ntohll (GNUNET_CRYPTO_random_u64 | ||
3740 | (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX)); | ||
3741 | msg_ctx.replication = DHT_DEFAULT_FIND_PEER_REPLICATION; | ||
3742 | msg_ctx.msg_options = GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE; | ||
3743 | msg_ctx.network_size = log_of_network_size_estimate; | ||
3744 | msg_ctx.peer = my_identity; | ||
3745 | msg_ctx.importance = DHT_DEFAULT_FIND_PEER_IMPORTANCE; | ||
3746 | msg_ctx.timeout = DHT_DEFAULT_FIND_PEER_TIMEOUT; | ||
3747 | |||
3748 | demultiplex_message (&find_peer_msg->header, &msg_ctx); | ||
3749 | GNUNET_free (find_peer_msg); | ||
3750 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3751 | "`%s:%s': Sent `%s' request to some (?) peers\n", my_short_id, | ||
3752 | "DHT", "FIND PEER"); | ||
3753 | if (newly_found_peers < bucket_size) | ||
3754 | { | ||
3755 | next_send_time.rel_value = | ||
3756 | (DHT_MAXIMUM_FIND_PEER_INTERVAL.rel_value / 2) + | ||
3757 | GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, | ||
3758 | DHT_MAXIMUM_FIND_PEER_INTERVAL.rel_value / 2); | ||
3759 | } | ||
3760 | else | ||
3761 | { | ||
3762 | next_send_time.rel_value = | ||
3763 | DHT_MINIMUM_FIND_PEER_INTERVAL.rel_value + | ||
3764 | GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, | ||
3765 | DHT_MAXIMUM_FIND_PEER_INTERVAL.rel_value - | ||
3766 | DHT_MINIMUM_FIND_PEER_INTERVAL.rel_value); | ||
3767 | } | ||
3768 | |||
3769 | GNUNET_assert (next_send_time.rel_value != 0); | ||
3770 | find_peer_context.count = 0; | ||
3771 | newly_found_peers = 0; | ||
3772 | find_peer_context.start = GNUNET_TIME_absolute_get (); | ||
3773 | if (GNUNET_YES == do_find_peer) | ||
3774 | { | ||
3775 | GNUNET_SCHEDULER_add_delayed (next_send_time, &send_find_peer_message, | ||
3776 | NULL); | ||
3777 | } | ||
3778 | } | ||
3779 | |||
3780 | /** | ||
3781 | * Handler for any generic DHT messages, calls the appropriate handler | ||
3782 | * depending on message type, sends confirmation if responses aren't otherwise | ||
3783 | * expected. | ||
3784 | * | ||
3785 | * @param cls closure for the service | ||
3786 | * @param client the client we received this message from | ||
3787 | * @param message the actual message received | ||
3788 | */ | ||
3789 | static void | ||
3790 | handle_dht_local_route_request (void *cls, struct GNUNET_SERVER_Client *client, | ||
3791 | const struct GNUNET_MessageHeader *message) | ||
3792 | { | ||
3793 | const struct GNUNET_DHT_RouteMessage *dht_msg = | ||
3794 | (const struct GNUNET_DHT_RouteMessage *) message; | ||
3795 | const struct GNUNET_MessageHeader *enc_msg; | ||
3796 | struct DHT_MessageContext msg_ctx; | ||
3797 | |||
3798 | enc_msg = (const struct GNUNET_MessageHeader *) &dht_msg[1]; | ||
3799 | #if DEBUG_DHT | ||
3800 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3801 | "`%s:%s': Received `%s' request from client, message type %d, key %s, uid %llu\n", | ||
3802 | my_short_id, "DHT", "GENERIC", ntohs (message->type), | ||
3803 | GNUNET_h2s (&dht_msg->key), GNUNET_ntohll (dht_msg->unique_id)); | ||
3804 | #endif | ||
3805 | #if DEBUG_DHT_ROUTING | ||
3806 | if (dhtlog_handle != NULL) | ||
3807 | dhtlog_handle->insert_dhtkey (NULL, &dht_msg->key); | ||
3808 | #endif | ||
3809 | |||
3810 | memset (&msg_ctx, 0, sizeof (struct DHT_MessageContext)); | ||
3811 | msg_ctx.client = find_active_client (client); | ||
3812 | memcpy (&msg_ctx.key, &dht_msg->key, sizeof (GNUNET_HashCode)); | ||
3813 | msg_ctx.unique_id = GNUNET_ntohll (dht_msg->unique_id); | ||
3814 | msg_ctx.replication = ntohl (dht_msg->desired_replication_level); | ||
3815 | msg_ctx.msg_options = ntohl (dht_msg->options); | ||
3816 | if (GNUNET_DHT_RO_RECORD_ROUTE == | ||
3817 | (msg_ctx.msg_options & GNUNET_DHT_RO_RECORD_ROUTE)) | ||
3818 | { | ||
3819 | msg_ctx.path_history = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity)); | ||
3820 | memcpy (msg_ctx.path_history, &my_identity, | ||
3821 | sizeof (struct GNUNET_PeerIdentity)); | ||
3822 | msg_ctx.path_history_len = 1; | ||
3823 | } | ||
3824 | msg_ctx.network_size = log_of_network_size_estimate; | ||
3825 | msg_ctx.peer = my_identity; | ||
3826 | msg_ctx.importance = DHT_DEFAULT_P2P_IMPORTANCE + 4; /* Make local routing a higher priority */ | ||
3827 | msg_ctx.timeout = DHT_DEFAULT_P2P_TIMEOUT; | ||
3828 | |||
3829 | if (ntohs (enc_msg->type) == GNUNET_MESSAGE_TYPE_DHT_GET) | ||
3830 | increment_stats (STAT_GET_START); | ||
3831 | else if (ntohs (enc_msg->type) == GNUNET_MESSAGE_TYPE_DHT_PUT) | ||
3832 | increment_stats (STAT_PUT_START); | ||
3833 | else if (ntohs (enc_msg->type) == GNUNET_MESSAGE_TYPE_DHT_FIND_PEER) | ||
3834 | increment_stats (STAT_FIND_PEER_START); | ||
3835 | |||
3836 | if (GNUNET_YES == malicious_dropper) | ||
3837 | { | ||
3838 | if (ntohs (enc_msg->type) == GNUNET_MESSAGE_TYPE_DHT_GET) | ||
3839 | { | ||
3840 | #if DEBUG_DHT_ROUTING | ||
3841 | if ((debug_routes) && (dhtlog_handle != NULL)) | ||
3842 | { | ||
3843 | dhtlog_handle->insert_query (NULL, msg_ctx.unique_id, DHTLOG_GET, | ||
3844 | msg_ctx.hop_count, GNUNET_NO, &my_identity, | ||
3845 | &msg_ctx.key); | ||
3846 | } | ||
3847 | #endif | ||
3848 | } | ||
3849 | else if (ntohs (enc_msg->type) == GNUNET_MESSAGE_TYPE_DHT_PUT) | ||
3850 | { | ||
3851 | #if DEBUG_DHT_ROUTING | ||
3852 | if ((debug_routes) && (dhtlog_handle != NULL)) | ||
3853 | { | ||
3854 | dhtlog_handle->insert_query (NULL, msg_ctx.unique_id, DHTLOG_PUT, | ||
3855 | msg_ctx.hop_count, GNUNET_NO, &my_identity, | ||
3856 | &msg_ctx.key); | ||
3857 | } | ||
3858 | #endif | ||
3859 | } | ||
3860 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
3861 | GNUNET_free_non_null (msg_ctx.path_history); | ||
3862 | return; | ||
3863 | } | ||
3864 | |||
3865 | demultiplex_message (enc_msg, &msg_ctx); | ||
3866 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
3867 | |||
3868 | } | ||
3869 | |||
3870 | /** | ||
3871 | * Handler for any locally received DHT control messages, | ||
3872 | * sets malicious flags mostly for now. | ||
3873 | * | ||
3874 | * @param cls closure for the service | ||
3875 | * @param client the client we received this message from | ||
3876 | * @param message the actual message received | ||
3877 | * | ||
3878 | */ | ||
3879 | static void | ||
3880 | handle_dht_control_message (void *cls, struct GNUNET_SERVER_Client *client, | ||
3881 | const struct GNUNET_MessageHeader *message) | ||
3882 | { | ||
3883 | const struct GNUNET_DHT_ControlMessage *dht_control_msg = | ||
3884 | (const struct GNUNET_DHT_ControlMessage *) message; | ||
3885 | |||
3886 | #if DEBUG_DHT | ||
3887 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3888 | "`%s:%s': Received `%s' request from client, command %d\n", | ||
3889 | my_short_id, "DHT", "CONTROL", ntohs (dht_control_msg->command)); | ||
3890 | #endif | ||
3891 | |||
3892 | switch (ntohs (dht_control_msg->command)) | ||
3893 | { | ||
3894 | case GNUNET_MESSAGE_TYPE_DHT_FIND_PEER: | ||
3895 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3896 | "Sending self seeking find peer request!\n"); | ||
3897 | GNUNET_SCHEDULER_add_now (&send_find_peer_message, NULL); | ||
3898 | break; | ||
3899 | #if HAVE_MALICIOUS | ||
3900 | case GNUNET_MESSAGE_TYPE_DHT_MALICIOUS_GET: | ||
3901 | if (ntohs (dht_control_msg->variable) > 0) | ||
3902 | malicious_get_frequency.rel_value = ntohs (dht_control_msg->variable); | ||
3903 | if (malicious_get_frequency.rel_value == 0) | ||
3904 | malicious_get_frequency = DEFAULT_MALICIOUS_GET_FREQUENCY; | ||
3905 | if (malicious_getter != GNUNET_YES) | ||
3906 | GNUNET_SCHEDULER_add_now (&malicious_get_task, NULL); | ||
3907 | malicious_getter = GNUNET_YES; | ||
3908 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3909 | "%s:%s Initiating malicious GET behavior, frequency %llu\n", | ||
3910 | my_short_id, "DHT", malicious_get_frequency.rel_value); | ||
3911 | break; | ||
3912 | case GNUNET_MESSAGE_TYPE_DHT_MALICIOUS_PUT: | ||
3913 | if (ntohs (dht_control_msg->variable) > 0) | ||
3914 | malicious_put_frequency.rel_value = ntohs (dht_control_msg->variable); | ||
3915 | if (malicious_put_frequency.rel_value == 0) | ||
3916 | malicious_put_frequency = DEFAULT_MALICIOUS_PUT_FREQUENCY; | ||
3917 | if (malicious_putter != GNUNET_YES) | ||
3918 | GNUNET_SCHEDULER_add_now (&malicious_put_task, NULL); | ||
3919 | malicious_putter = GNUNET_YES; | ||
3920 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3921 | "%s:%s Initiating malicious PUT behavior, frequency %d\n", | ||
3922 | my_short_id, "DHT", malicious_put_frequency); | ||
3923 | break; | ||
3924 | case GNUNET_MESSAGE_TYPE_DHT_MALICIOUS_DROP: | ||
3925 | #if DEBUG_DHT_ROUTING | ||
3926 | if ((malicious_dropper != GNUNET_YES) && (dhtlog_handle != NULL)) | ||
3927 | dhtlog_handle->set_malicious (&my_identity); | ||
3928 | #endif | ||
3929 | malicious_dropper = GNUNET_YES; | ||
3930 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3931 | "%s:%s Initiating malicious DROP behavior\n", my_short_id, | ||
3932 | "DHT"); | ||
3933 | break; | ||
3934 | #endif | ||
3935 | default: | ||
3936 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
3937 | "%s:%s Unknown control command type `%d'!\n", my_short_id, | ||
3938 | "DHT", ntohs (dht_control_msg->command)); | ||
3939 | break; | ||
3940 | } | ||
3941 | |||
3942 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
3943 | } | ||
3944 | |||
3945 | /** | ||
3946 | * Handler for any generic DHT stop messages, calls the appropriate handler | ||
3947 | * depending on message type (if processed locally) | ||
3948 | * | ||
3949 | * @param cls closure for the service | ||
3950 | * @param client the client we received this message from | ||
3951 | * @param message the actual message received | ||
3952 | * | ||
3953 | */ | ||
3954 | static void | ||
3955 | handle_dht_local_route_stop (void *cls, struct GNUNET_SERVER_Client *client, | ||
3956 | const struct GNUNET_MessageHeader *message) | ||
3957 | { | ||
3958 | |||
3959 | const struct GNUNET_DHT_StopMessage *dht_stop_msg = | ||
3960 | (const struct GNUNET_DHT_StopMessage *) message; | ||
3961 | struct DHTQueryRecord *record; | ||
3962 | struct DHTRouteSource *pos; | ||
3963 | |||
3964 | #if DEBUG_DHT | ||
3965 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3966 | "`%s:%s': Received `%s' request from client, uid %llu\n", | ||
3967 | my_short_id, "DHT", "GENERIC STOP", | ||
3968 | GNUNET_ntohll (dht_stop_msg->unique_id)); | ||
3969 | #endif | ||
3970 | record = | ||
3971 | GNUNET_CONTAINER_multihashmap_get (forward_list.hashmap, | ||
3972 | &dht_stop_msg->key); | ||
3973 | if (record != NULL) | ||
3974 | { | ||
3975 | pos = record->head; | ||
3976 | |||
3977 | while (pos != NULL) | ||
3978 | { | ||
3979 | /* If the client is non-null (local request) and the client matches the requesting client, remove the entry. */ | ||
3980 | if ((pos->client != NULL) && (pos->client->client_handle == client)) | ||
3981 | { | ||
3982 | if (pos->delete_task != GNUNET_SCHEDULER_NO_TASK) | ||
3983 | GNUNET_SCHEDULER_cancel (pos->delete_task); | ||
3984 | pos->delete_task = | ||
3985 | GNUNET_SCHEDULER_add_now (&remove_forward_entry, pos); | ||
3986 | } | ||
3987 | pos = pos->next; | ||
3988 | } | ||
3989 | } | ||
3990 | |||
3991 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
3992 | } | ||
3993 | |||
3994 | |||
3995 | /** | ||
3996 | * Core handler for p2p route requests. | ||
3997 | * | ||
3998 | * @param cls closure | ||
3999 | * @param message message | ||
4000 | * @param peer peer identity this notification is about | ||
4001 | * @param atsi performance data | ||
4002 | * @return GNUNET_OK to keep the connection open, | ||
4003 | * GNUNET_SYSERR to close it (signal serious error) | ||
4004 | */ | ||
4005 | static int | ||
4006 | handle_dht_p2p_route_request (void *cls, const struct GNUNET_PeerIdentity *peer, | ||
4007 | const struct GNUNET_MessageHeader *message, | ||
4008 | const struct GNUNET_TRANSPORT_ATS_Information | ||
4009 | *atsi) | ||
4010 | { | ||
4011 | #if DEBUG_DHT | ||
4012 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4013 | "`%s:%s': Received P2P request from peer %s\n", my_short_id, | ||
4014 | "DHT", GNUNET_i2s (peer)); | ||
4015 | #endif | ||
4016 | struct GNUNET_DHT_P2PRouteMessage *incoming = | ||
4017 | (struct GNUNET_DHT_P2PRouteMessage *) message; | ||
4018 | struct GNUNET_MessageHeader *enc_msg = | ||
4019 | (struct GNUNET_MessageHeader *) &incoming[1]; | ||
4020 | struct DHT_MessageContext *msg_ctx; | ||
4021 | char *route_path; | ||
4022 | int path_size; | ||
4023 | |||
4024 | if (ntohs (enc_msg->size) >= GNUNET_SERVER_MAX_MESSAGE_SIZE - 1) | ||
4025 | { | ||
4026 | GNUNET_break_op (0); | ||
4027 | return GNUNET_YES; | ||
4028 | } | ||
4029 | |||
4030 | if (malicious_dropper == GNUNET_YES) | ||
4031 | { | ||
4032 | #if DEBUG_DHT_ROUTING | ||
4033 | if ((debug_routes_extended) && (dhtlog_handle != NULL)) | ||
4034 | { | ||
4035 | /** Log routes that die due to high load! */ | ||
4036 | dhtlog_handle->insert_route (NULL, | ||
4037 | #if HAVE_UID_FOR_TESTING | ||
4038 | GNUNET_ntohll (incoming->unique_id), | ||
4039 | #else | ||
4040 | 0, | ||
4041 | #endif | ||
4042 | DHTLOG_ROUTE, ntohl (incoming->hop_count), | ||
4043 | GNUNET_SYSERR, &my_identity, &incoming->key, | ||
4044 | peer, NULL); | ||
4045 | } | ||
4046 | #endif | ||
4047 | return GNUNET_YES; | ||
4048 | } | ||
4049 | |||
4050 | if (get_max_send_delay ().rel_value > MAX_REQUEST_TIME.rel_value) | ||
4051 | { | ||
4052 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4053 | "Sending of previous replies took too long, backing off!\n"); | ||
4054 | increment_stats ("# route requests dropped due to high load"); | ||
4055 | decrease_max_send_delay (get_max_send_delay ()); | ||
4056 | #if DEBUG_DHT_ROUTING | ||
4057 | if ((debug_routes_extended) && (dhtlog_handle != NULL)) | ||
4058 | { | ||
4059 | /** Log routes that die due to high load! */ | ||
4060 | dhtlog_handle->insert_route (NULL, | ||
4061 | #if HAVE_UID_FOR_TESTING | ||
4062 | GNUNET_ntohll (incoming->unique_id), | ||
4063 | #else | ||
4064 | 0, | ||
4065 | #endif | ||
4066 | DHTLOG_ROUTE, ntohl (incoming->hop_count), | ||
4067 | GNUNET_SYSERR, &my_identity, &incoming->key, | ||
4068 | peer, NULL); | ||
4069 | } | ||
4070 | #endif | ||
4071 | return GNUNET_YES; | ||
4072 | } | ||
4073 | msg_ctx = GNUNET_malloc (sizeof (struct DHT_MessageContext)); | ||
4074 | msg_ctx->bloom = | ||
4075 | GNUNET_CONTAINER_bloomfilter_init (incoming->bloomfilter, DHT_BLOOM_SIZE, | ||
4076 | DHT_BLOOM_K); | ||
4077 | GNUNET_assert (msg_ctx->bloom != NULL); | ||
4078 | msg_ctx->hop_count = ntohl (incoming->hop_count); | ||
4079 | memcpy (&msg_ctx->key, &incoming->key, sizeof (GNUNET_HashCode)); | ||
4080 | msg_ctx->replication = ntohl (incoming->desired_replication_level); | ||
4081 | #if HAVE_UID_FOR_TESTING | ||
4082 | msg_ctx->unique_id = GNUNET_ntohll (incoming->unique_id); | ||
4083 | #endif | ||
4084 | msg_ctx->msg_options = ntohl (incoming->options); | ||
4085 | if (GNUNET_DHT_RO_RECORD_ROUTE == | ||
4086 | (msg_ctx->msg_options & GNUNET_DHT_RO_RECORD_ROUTE)) | ||
4087 | { | ||
4088 | path_size = | ||
4089 | ntohl (incoming->outgoing_path_length) * | ||
4090 | sizeof (struct GNUNET_PeerIdentity); | ||
4091 | if (ntohs (message->size) != | ||
4092 | (sizeof (struct GNUNET_DHT_P2PRouteMessage) + ntohs (enc_msg->size) + | ||
4093 | path_size)) | ||
4094 | { | ||
4095 | GNUNET_break_op (0); | ||
4096 | GNUNET_free (msg_ctx); | ||
4097 | return GNUNET_YES; | ||
4098 | } | ||
4099 | route_path = (char *) &incoming[1]; | ||
4100 | route_path = route_path + ntohs (enc_msg->size); | ||
4101 | msg_ctx->path_history = | ||
4102 | GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity) + path_size); | ||
4103 | memcpy (msg_ctx->path_history, route_path, path_size); | ||
4104 | memcpy (&msg_ctx->path_history[path_size], &my_identity, | ||
4105 | sizeof (struct GNUNET_PeerIdentity)); | ||
4106 | msg_ctx->path_history_len = ntohl (incoming->outgoing_path_length) + 1; | ||
4107 | } | ||
4108 | msg_ctx->network_size = ntohl (incoming->network_size); | ||
4109 | msg_ctx->peer = *peer; | ||
4110 | msg_ctx->importance = DHT_DEFAULT_P2P_IMPORTANCE; | ||
4111 | msg_ctx->timeout = DHT_DEFAULT_P2P_TIMEOUT; | ||
4112 | demultiplex_message (enc_msg, msg_ctx); | ||
4113 | if (msg_ctx->bloom != NULL) | ||
4114 | { | ||
4115 | GNUNET_CONTAINER_bloomfilter_free (msg_ctx->bloom); | ||
4116 | msg_ctx->bloom = NULL; | ||
4117 | } | ||
4118 | GNUNET_free (msg_ctx); | ||
4119 | return GNUNET_YES; | ||
4120 | } | ||
4121 | |||
4122 | |||
4123 | /** | ||
4124 | * Core handler for p2p route results. | ||
4125 | * | ||
4126 | * @param cls closure | ||
4127 | * @param message message | ||
4128 | * @param peer peer identity this notification is about | ||
4129 | * @param atsi performance data | ||
4130 | * | ||
4131 | */ | ||
4132 | static int | ||
4133 | handle_dht_p2p_route_result (void *cls, const struct GNUNET_PeerIdentity *peer, | ||
4134 | const struct GNUNET_MessageHeader *message, | ||
4135 | const struct GNUNET_TRANSPORT_ATS_Information | ||
4136 | *atsi) | ||
4137 | { | ||
4138 | #if DEBUG_DHT | ||
4139 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4140 | "`%s:%s': Received request from peer %s\n", my_short_id, "DHT", | ||
4141 | GNUNET_i2s (peer)); | ||
4142 | #endif | ||
4143 | const struct GNUNET_DHT_P2PRouteResultMessage *incoming = | ||
4144 | (const struct GNUNET_DHT_P2PRouteResultMessage *) message; | ||
4145 | struct GNUNET_MessageHeader *enc_msg = | ||
4146 | (struct GNUNET_MessageHeader *) &incoming[1]; | ||
4147 | struct DHT_MessageContext msg_ctx; | ||
4148 | |||
4149 | #if DEBUG_PATH | ||
4150 | char *path_offset; | ||
4151 | unsigned int i; | ||
4152 | #endif | ||
4153 | if (ntohs (enc_msg->size) >= GNUNET_SERVER_MAX_MESSAGE_SIZE - 1) | ||
4154 | { | ||
4155 | GNUNET_break_op (0); | ||
4156 | return GNUNET_YES; | ||
4157 | } | ||
4158 | |||
4159 | if (malicious_dropper == GNUNET_YES) | ||
4160 | { | ||
4161 | #if DEBUG_DHT_ROUTING | ||
4162 | if ((debug_routes_extended) && (dhtlog_handle != NULL)) | ||
4163 | { | ||
4164 | /** Log routes that die due to high load! */ | ||
4165 | dhtlog_handle->insert_route (NULL, | ||
4166 | #if HAVE_UID_FOR_TESTING | ||
4167 | GNUNET_ntohll (incoming->unique_id), | ||
4168 | #else | ||
4169 | 0, | ||
4170 | #endif | ||
4171 | DHTLOG_ROUTE, ntohl (incoming->hop_count), | ||
4172 | GNUNET_SYSERR, &my_identity, &incoming->key, | ||
4173 | peer, NULL); | ||
4174 | } | ||
4175 | #endif | ||
4176 | return GNUNET_YES; | ||
4177 | } | ||
4178 | |||
4179 | memset (&msg_ctx, 0, sizeof (struct DHT_MessageContext)); | ||
4180 | memcpy (&msg_ctx.key, &incoming->key, sizeof (GNUNET_HashCode)); | ||
4181 | #if HAVE_UID_FOR_TESTING | ||
4182 | msg_ctx.unique_id = GNUNET_ntohll (incoming->unique_id); | ||
4183 | #endif | ||
4184 | msg_ctx.msg_options = ntohl (incoming->options); | ||
4185 | msg_ctx.hop_count = ntohl (incoming->hop_count); | ||
4186 | msg_ctx.peer = *peer; | ||
4187 | msg_ctx.importance = DHT_DEFAULT_P2P_IMPORTANCE + 2; /* Make result routing a higher priority */ | ||
4188 | msg_ctx.timeout = DHT_DEFAULT_P2P_TIMEOUT; | ||
4189 | if ((GNUNET_DHT_RO_RECORD_ROUTE == | ||
4190 | (msg_ctx.msg_options & GNUNET_DHT_RO_RECORD_ROUTE)) && | ||
4191 | (ntohl (incoming->outgoing_path_length) > 0)) | ||
4192 | { | ||
4193 | if (ntohs (message->size) - | ||
4194 | sizeof (struct GNUNET_DHT_P2PRouteResultMessage) - | ||
4195 | ntohs (enc_msg->size) != | ||
4196 | ntohl (incoming->outgoing_path_length) * | ||
4197 | sizeof (struct GNUNET_PeerIdentity)) | ||
4198 | { | ||
4199 | #if DEBUG_DHT | ||
4200 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4201 | "Return message indicated a path was included, but sizes are wrong: Total size %d, enc size %d, left %d, expected %d\n", | ||
4202 | ntohs (message->size), ntohs (enc_msg->size), | ||
4203 | ntohs (message->size) - | ||
4204 | sizeof (struct GNUNET_DHT_P2PRouteResultMessage) - | ||
4205 | ntohs (enc_msg->size), | ||
4206 | ntohl (incoming->outgoing_path_length) * | ||
4207 | sizeof (struct GNUNET_PeerIdentity)); | ||
4208 | #endif | ||
4209 | GNUNET_break_op (0); | ||
4210 | return GNUNET_NO; | ||
4211 | } | ||
4212 | msg_ctx.path_history = (char *) &incoming[1]; | ||
4213 | msg_ctx.path_history += ntohs (enc_msg->size); | ||
4214 | msg_ctx.path_history_len = ntohl (incoming->outgoing_path_length); | ||
4215 | #if DEBUG_PATH | ||
4216 | for (i = 0; i < msg_ctx.path_history_len; i++) | ||
4217 | { | ||
4218 | path_offset = | ||
4219 | &msg_ctx.path_history[i * sizeof (struct GNUNET_PeerIdentity)]; | ||
4220 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4221 | "(handle_p2p_route_result) Key %s Found peer %d:%s\n", | ||
4222 | GNUNET_h2s (&msg_ctx.key), i, | ||
4223 | GNUNET_i2s ((struct GNUNET_PeerIdentity *) path_offset)); | ||
4224 | } | ||
4225 | #endif | ||
4226 | } | ||
4227 | route_result_message (enc_msg, &msg_ctx); | ||
4228 | return GNUNET_YES; | ||
4229 | } | ||
4230 | |||
4231 | |||
4232 | /** | ||
4233 | * Receive the HELLO from transport service, | ||
4234 | * free current and replace if necessary. | ||
4235 | * | ||
4236 | * @param cls NULL | ||
4237 | * @param message HELLO message of peer | ||
4238 | */ | ||
4239 | static void | ||
4240 | process_hello (void *cls, const struct GNUNET_MessageHeader *message) | ||
4241 | { | ||
4242 | #if DEBUG_DHT | ||
4243 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4244 | "Received our `%s' from transport service\n", "HELLO"); | ||
4245 | #endif | ||
4246 | |||
4247 | GNUNET_assert (message != NULL); | ||
4248 | GNUNET_free_non_null (my_hello); | ||
4249 | my_hello = GNUNET_malloc (ntohs (message->size)); | ||
4250 | memcpy (my_hello, message, ntohs (message->size)); | ||
4251 | } | ||
4252 | |||
4253 | |||
4254 | /** | ||
4255 | * Task run during shutdown. | ||
4256 | * | ||
4257 | * @param cls unused | ||
4258 | * @param tc unused | ||
4259 | */ | ||
4260 | static void | ||
4261 | shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
4262 | { | ||
4263 | int bucket_count; | ||
4264 | struct PeerInfo *pos; | ||
4265 | |||
4266 | if (NULL != ghh) | ||
4267 | { | ||
4268 | GNUNET_TRANSPORT_get_hello_cancel (ghh); | ||
4269 | ghh = NULL; | ||
4270 | } | ||
4271 | if (transport_handle != NULL) | ||
4272 | { | ||
4273 | GNUNET_free_non_null (my_hello); | ||
4274 | GNUNET_TRANSPORT_disconnect (transport_handle); | ||
4275 | transport_handle = NULL; | ||
4276 | } | ||
4277 | if (NULL != nse) | ||
4278 | { | ||
4279 | GNUNET_NSE_disconnect (nse); | ||
4280 | nse = NULL; | ||
4281 | } | ||
4282 | if (coreAPI != NULL) | ||
4283 | { | ||
4284 | #if DEBUG_DHT | ||
4285 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s:%s Disconnecting core!\n", | ||
4286 | my_short_id, "DHT"); | ||
4287 | #endif | ||
4288 | GNUNET_CORE_disconnect (coreAPI); | ||
4289 | coreAPI = NULL; | ||
4290 | } | ||
4291 | for (bucket_count = lowest_bucket; bucket_count < MAX_BUCKETS; bucket_count++) | ||
4292 | { | ||
4293 | while (k_buckets[bucket_count].head != NULL) | ||
4294 | { | ||
4295 | pos = k_buckets[bucket_count].head; | ||
4296 | #if DEBUG_DHT | ||
4297 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4298 | "%s:%s Removing peer %s from bucket %d!\n", my_short_id, | ||
4299 | "DHT", GNUNET_i2s (&pos->id), bucket_count); | ||
4300 | #endif | ||
4301 | delete_peer (pos, bucket_count); | ||
4302 | } | ||
4303 | } | ||
4304 | if (datacache != NULL) | ||
4305 | { | ||
4306 | #if DEBUG_DHT | ||
4307 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s:%s Destroying datacache!\n", | ||
4308 | my_short_id, "DHT"); | ||
4309 | #endif | ||
4310 | GNUNET_DATACACHE_destroy (datacache); | ||
4311 | datacache = NULL; | ||
4312 | } | ||
4313 | if (stats != NULL) | ||
4314 | { | ||
4315 | GNUNET_STATISTICS_destroy (stats, GNUNET_YES); | ||
4316 | stats = NULL; | ||
4317 | } | ||
4318 | if (dhtlog_handle != NULL) | ||
4319 | { | ||
4320 | GNUNET_DHTLOG_disconnect (dhtlog_handle); | ||
4321 | dhtlog_handle = NULL; | ||
4322 | } | ||
4323 | if (block_context != NULL) | ||
4324 | { | ||
4325 | GNUNET_BLOCK_context_destroy (block_context); | ||
4326 | block_context = NULL; | ||
4327 | } | ||
4328 | GNUNET_free_non_null (my_short_id); | ||
4329 | my_short_id = NULL; | ||
4330 | } | ||
4331 | |||
4332 | |||
4333 | /** | ||
4334 | * To be called on core init/fail. | ||
4335 | * | ||
4336 | * @param cls service closure | ||
4337 | * @param server handle to the server for this service | ||
4338 | * @param identity the public identity of this peer | ||
4339 | * @param publicKey the public key of this peer | ||
4340 | */ | ||
4341 | static void | ||
4342 | core_init (void *cls, struct GNUNET_CORE_Handle *server, | ||
4343 | const struct GNUNET_PeerIdentity *identity, | ||
4344 | const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey) | ||
4345 | { | ||
4346 | |||
4347 | if (server == NULL) | ||
4348 | { | ||
4349 | #if DEBUG_DHT | ||
4350 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Connection to core FAILED!\n", | ||
4351 | "dht", GNUNET_i2s (identity)); | ||
4352 | #endif | ||
4353 | GNUNET_SCHEDULER_cancel (cleanup_task); | ||
4354 | GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); | ||
4355 | return; | ||
4356 | } | ||
4357 | #if DEBUG_DHT | ||
4358 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4359 | "%s: Core connection initialized, I am peer: %s\n", "dht", | ||
4360 | GNUNET_i2s (identity)); | ||
4361 | #endif | ||
4362 | |||
4363 | /* Copy our identity so we can use it */ | ||
4364 | memcpy (&my_identity, identity, sizeof (struct GNUNET_PeerIdentity)); | ||
4365 | if (my_short_id != NULL) | ||
4366 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
4367 | "%s Receive CORE INIT message but have already been initialized! Did CORE fail?\n", | ||
4368 | "DHT SERVICE"); | ||
4369 | my_short_id = GNUNET_strdup (GNUNET_i2s (&my_identity)); | ||
4370 | if (dhtlog_handle != NULL) | ||
4371 | dhtlog_handle->insert_node (NULL, &my_identity); | ||
4372 | } | ||
4373 | |||
4374 | |||
4375 | static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = { | ||
4376 | {&handle_dht_local_route_request, NULL, GNUNET_MESSAGE_TYPE_DHT_LOCAL_ROUTE, | ||
4377 | 0}, | ||
4378 | {&handle_dht_local_route_stop, NULL, | ||
4379 | GNUNET_MESSAGE_TYPE_DHT_LOCAL_ROUTE_STOP, 0}, | ||
4380 | {&handle_dht_control_message, NULL, GNUNET_MESSAGE_TYPE_DHT_CONTROL, 0}, | ||
4381 | {NULL, NULL, 0, 0} | ||
4382 | }; | ||
4383 | |||
4384 | |||
4385 | static struct GNUNET_CORE_MessageHandler core_handlers[] = { | ||
4386 | {&handle_dht_p2p_route_request, GNUNET_MESSAGE_TYPE_DHT_P2P_ROUTE, 0}, | ||
4387 | {&handle_dht_p2p_route_result, GNUNET_MESSAGE_TYPE_DHT_P2P_ROUTE_RESULT, 0}, | ||
4388 | {NULL, 0, 0} | ||
4389 | }; | ||
4390 | |||
4391 | |||
4392 | /** | ||
4393 | * Method called whenever a peer connects. | ||
4394 | * | ||
4395 | * @param cls closure | ||
4396 | * @param peer peer identity this notification is about | ||
4397 | * @param atsi performance data | ||
4398 | */ | ||
4399 | static void | ||
4400 | handle_core_connect (void *cls, const struct GNUNET_PeerIdentity *peer, | ||
4401 | const struct GNUNET_TRANSPORT_ATS_Information *atsi) | ||
4402 | { | ||
4403 | struct PeerInfo *ret; | ||
4404 | struct DHTPutEntry *put_entry; | ||
4405 | int peer_bucket; | ||
4406 | |||
4407 | /* Check for connect to self message */ | ||
4408 | if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity))) | ||
4409 | return; | ||
4410 | |||
4411 | #if DEBUG_DHT | ||
4412 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4413 | "%s:%s Receives core connect message for peer %s distance %d!\n", | ||
4414 | my_short_id, "dht", GNUNET_i2s (peer), distance); | ||
4415 | #endif | ||
4416 | |||
4417 | if (GNUNET_YES == | ||
4418 | GNUNET_CONTAINER_multihashmap_contains (all_known_peers, | ||
4419 | &peer->hashPubKey)) | ||
4420 | { | ||
4421 | #if DEBUG_DHT | ||
4422 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4423 | "%s:%s Received %s message for peer %s, but already have peer in RT!", | ||
4424 | my_short_id, "DHT", "CORE CONNECT", GNUNET_i2s (peer)); | ||
4425 | #endif | ||
4426 | GNUNET_break (0); | ||
4427 | return; | ||
4428 | } | ||
4429 | |||
4430 | if ((datacache != NULL) && (GNUNET_YES == put_peer_identities)) | ||
4431 | { | ||
4432 | put_entry = | ||
4433 | GNUNET_malloc (sizeof (struct DHTPutEntry) + | ||
4434 | sizeof (struct GNUNET_PeerIdentity)); | ||
4435 | put_entry->path_length = 0; | ||
4436 | put_entry->data_size = sizeof (struct GNUNET_PeerIdentity); | ||
4437 | memcpy (&put_entry[1], peer, sizeof (struct GNUNET_PeerIdentity)); | ||
4438 | GNUNET_DATACACHE_put (datacache, &peer->hashPubKey, | ||
4439 | sizeof (struct DHTPutEntry) + | ||
4440 | sizeof (struct GNUNET_PeerIdentity), | ||
4441 | (char *) put_entry, GNUNET_BLOCK_TYPE_DHT_HELLO, | ||
4442 | GNUNET_TIME_absolute_get_forever ()); | ||
4443 | GNUNET_free (put_entry); | ||
4444 | } | ||
4445 | else if (datacache == NULL) | ||
4446 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
4447 | "DHT has no connection to datacache!\n"); | ||
4448 | |||
4449 | peer_bucket = find_current_bucket (&peer->hashPubKey); | ||
4450 | GNUNET_assert (peer_bucket >= lowest_bucket); | ||
4451 | GNUNET_assert (peer_bucket < MAX_BUCKETS); | ||
4452 | ret = GNUNET_malloc (sizeof (struct PeerInfo)); | ||
4453 | #if 0 | ||
4454 | ret->latency = latency; | ||
4455 | ret->distance = distance; | ||
4456 | #endif | ||
4457 | ret->id = *peer; | ||
4458 | GNUNET_CONTAINER_DLL_insert_after (k_buckets[peer_bucket].head, | ||
4459 | k_buckets[peer_bucket].tail, | ||
4460 | k_buckets[peer_bucket].tail, ret); | ||
4461 | k_buckets[peer_bucket].peers_size++; | ||
4462 | #if DO_UPDATE_PREFERENCE | ||
4463 | if ((GNUNET_CRYPTO_hash_matching_bits | ||
4464 | (&my_identity.hashPubKey, &peer->hashPubKey) > 0) && | ||
4465 | (k_buckets[peer_bucket].peers_size <= bucket_size)) | ||
4466 | ret->preference_task = | ||
4467 | GNUNET_SCHEDULER_add_now (&update_core_preference, ret); | ||
4468 | #endif | ||
4469 | if ((k_buckets[lowest_bucket].peers_size) >= bucket_size) | ||
4470 | enable_next_bucket (); | ||
4471 | newly_found_peers++; | ||
4472 | GNUNET_CONTAINER_multihashmap_put (all_known_peers, &peer->hashPubKey, ret, | ||
4473 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | ||
4474 | increment_stats (STAT_PEERS_KNOWN); | ||
4475 | |||
4476 | #if DEBUG_DHT | ||
4477 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4478 | "%s:%s Adding peer to routing list: %s\n", my_short_id, "DHT", | ||
4479 | ret == NULL ? "NOT ADDED" : "PEER ADDED"); | ||
4480 | #endif | ||
4481 | } | ||
4482 | |||
4483 | |||
4484 | /** | ||
4485 | * Method called whenever a peer disconnects. | ||
4486 | * | ||
4487 | * @param cls closure | ||
4488 | * @param peer peer identity this notification is about | ||
4489 | */ | ||
4490 | static void | ||
4491 | handle_core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer) | ||
4492 | { | ||
4493 | struct PeerInfo *to_remove; | ||
4494 | int current_bucket; | ||
4495 | |||
4496 | /* Check for disconnect from self message */ | ||
4497 | if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity))) | ||
4498 | return; | ||
4499 | #if DEBUG_DHT | ||
4500 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4501 | "%s:%s: Received peer disconnect message for peer `%s' from %s\n", | ||
4502 | my_short_id, "DHT", GNUNET_i2s (peer), "CORE"); | ||
4503 | #endif | ||
4504 | |||
4505 | if (GNUNET_YES != | ||
4506 | GNUNET_CONTAINER_multihashmap_contains (all_known_peers, | ||
4507 | &peer->hashPubKey)) | ||
4508 | { | ||
4509 | GNUNET_break (0); | ||
4510 | #if DEBUG_DHT | ||
4511 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4512 | "%s:%s: do not have peer `%s' in RT, can't disconnect!\n", | ||
4513 | my_short_id, "DHT", GNUNET_i2s (peer)); | ||
4514 | #endif | ||
4515 | return; | ||
4516 | } | ||
4517 | increment_stats (STAT_DISCONNECTS); | ||
4518 | GNUNET_assert (GNUNET_CONTAINER_multihashmap_contains | ||
4519 | (all_known_peers, &peer->hashPubKey)); | ||
4520 | to_remove = | ||
4521 | GNUNET_CONTAINER_multihashmap_get (all_known_peers, &peer->hashPubKey); | ||
4522 | GNUNET_assert (to_remove != NULL); | ||
4523 | if (NULL != to_remove->info_ctx) | ||
4524 | { | ||
4525 | GNUNET_CORE_peer_change_preference_cancel (to_remove->info_ctx); | ||
4526 | to_remove->info_ctx = NULL; | ||
4527 | } | ||
4528 | GNUNET_assert (0 == | ||
4529 | memcmp (peer, &to_remove->id, | ||
4530 | sizeof (struct GNUNET_PeerIdentity))); | ||
4531 | current_bucket = find_current_bucket (&to_remove->id.hashPubKey); | ||
4532 | delete_peer (to_remove, current_bucket); | ||
4533 | } | ||
4534 | |||
4535 | |||
4536 | /** | ||
4537 | * Process dht requests. | ||
4538 | * | ||
4539 | * @param cls closure | ||
4540 | * @param server the initialized server | ||
4541 | * @param c configuration to use | ||
4542 | */ | ||
4543 | static void | ||
4544 | run (void *cls, struct GNUNET_SERVER_Handle *server, | ||
4545 | const struct GNUNET_CONFIGURATION_Handle *c) | ||
4546 | { | ||
4547 | struct GNUNET_TIME_Relative next_send_time; | ||
4548 | unsigned long long temp_config_num; | ||
4549 | |||
4550 | cfg = c; | ||
4551 | datacache = GNUNET_DATACACHE_create (cfg, "dhtcache"); | ||
4552 | GNUNET_SERVER_add_handlers (server, plugin_handlers); | ||
4553 | GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL); | ||
4554 | nse = GNUNET_NSE_connect (cfg, &update_network_size_estimate, NULL); | ||
4555 | coreAPI = GNUNET_CORE_connect (cfg, /* Main configuration */ | ||
4556 | DEFAULT_CORE_QUEUE_SIZE, /* queue size */ | ||
4557 | NULL, /* Closure passed to DHT functions */ | ||
4558 | &core_init, /* Call core_init once connected */ | ||
4559 | &handle_core_connect, /* Handle connects */ | ||
4560 | &handle_core_disconnect, /* remove peers on disconnects */ | ||
4561 | NULL, /* Do we care about "status" updates? */ | ||
4562 | NULL, /* Don't want notified about all incoming messages */ | ||
4563 | GNUNET_NO, /* For header only inbound notification */ | ||
4564 | NULL, /* Don't want notified about all outbound messages */ | ||
4565 | GNUNET_NO, /* For header only outbound notification */ | ||
4566 | core_handlers); /* Register these handlers */ | ||
4567 | |||
4568 | if (coreAPI == NULL) | ||
4569 | return; | ||
4570 | transport_handle = | ||
4571 | GNUNET_TRANSPORT_connect (cfg, NULL, NULL, NULL, NULL, NULL); | ||
4572 | if (transport_handle != NULL) | ||
4573 | ghh = GNUNET_TRANSPORT_get_hello (transport_handle, &process_hello, NULL); | ||
4574 | else | ||
4575 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
4576 | "Failed to connect to transport service!\n"); | ||
4577 | block_context = GNUNET_BLOCK_context_create (cfg); | ||
4578 | lowest_bucket = MAX_BUCKETS - 1; | ||
4579 | forward_list.hashmap = | ||
4580 | GNUNET_CONTAINER_multihashmap_create (MAX_OUTSTANDING_FORWARDS / 10); | ||
4581 | forward_list.minHeap = | ||
4582 | GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); | ||
4583 | all_known_peers = GNUNET_CONTAINER_multihashmap_create (MAX_BUCKETS / 8); | ||
4584 | GNUNET_assert (all_known_peers != NULL); | ||
4585 | if (GNUNET_YES == | ||
4586 | GNUNET_CONFIGURATION_get_value_yesno (cfg, "dht_testing", | ||
4587 | "mysql_logging")) | ||
4588 | { | ||
4589 | debug_routes = GNUNET_YES; | ||
4590 | } | ||
4591 | |||
4592 | if (GNUNET_YES == | ||
4593 | GNUNET_CONFIGURATION_get_value_yesno (cfg, "dht", "strict_kademlia")) | ||
4594 | { | ||
4595 | strict_kademlia = GNUNET_YES; | ||
4596 | } | ||
4597 | |||
4598 | if (GNUNET_YES == | ||
4599 | GNUNET_CONFIGURATION_get_value_yesno (cfg, "dht", "stop_on_closest")) | ||
4600 | { | ||
4601 | stop_on_closest = GNUNET_YES; | ||
4602 | } | ||
4603 | |||
4604 | if (GNUNET_YES == | ||
4605 | GNUNET_CONFIGURATION_get_value_yesno (cfg, "dht", "stop_found")) | ||
4606 | { | ||
4607 | stop_on_found = GNUNET_YES; | ||
4608 | } | ||
4609 | |||
4610 | if (GNUNET_YES == | ||
4611 | GNUNET_CONFIGURATION_get_value_yesno (cfg, "dht", "malicious_getter")) | ||
4612 | { | ||
4613 | malicious_getter = GNUNET_YES; | ||
4614 | if (GNUNET_NO == | ||
4615 | GNUNET_CONFIGURATION_get_value_time (cfg, "DHT", | ||
4616 | "MALICIOUS_GET_FREQUENCY", | ||
4617 | &malicious_get_frequency)) | ||
4618 | malicious_get_frequency = DEFAULT_MALICIOUS_GET_FREQUENCY; | ||
4619 | } | ||
4620 | |||
4621 | if (GNUNET_YES == | ||
4622 | GNUNET_CONFIGURATION_get_value_yesno (cfg, "dht", "malicious_putter")) | ||
4623 | { | ||
4624 | malicious_putter = GNUNET_YES; | ||
4625 | if (GNUNET_NO == | ||
4626 | GNUNET_CONFIGURATION_get_value_time (cfg, "DHT", | ||
4627 | "MALICIOUS_PUT_FREQUENCY", | ||
4628 | &malicious_put_frequency)) | ||
4629 | malicious_put_frequency = DEFAULT_MALICIOUS_PUT_FREQUENCY; | ||
4630 | } | ||
4631 | |||
4632 | if (GNUNET_OK == | ||
4633 | GNUNET_CONFIGURATION_get_value_number (cfg, "DHT", "bucket_size", | ||
4634 | &temp_config_num)) | ||
4635 | { | ||
4636 | bucket_size = (unsigned int) temp_config_num; | ||
4637 | } | ||
4638 | |||
4639 | if (GNUNET_OK != | ||
4640 | GNUNET_CONFIGURATION_get_value_number (cfg, "DHT", "kad_alpha", | ||
4641 | &kademlia_replication)) | ||
4642 | { | ||
4643 | kademlia_replication = DEFAULT_KADEMLIA_REPLICATION; | ||
4644 | } | ||
4645 | |||
4646 | if (GNUNET_YES == | ||
4647 | GNUNET_CONFIGURATION_get_value_yesno (cfg, "dht", "malicious_dropper")) | ||
4648 | { | ||
4649 | malicious_dropper = GNUNET_YES; | ||
4650 | } | ||
4651 | |||
4652 | if (GNUNET_NO == | ||
4653 | GNUNET_CONFIGURATION_get_value_yesno (cfg, "dht", "do_find_peer")) | ||
4654 | { | ||
4655 | do_find_peer = GNUNET_NO; | ||
4656 | } | ||
4657 | else | ||
4658 | do_find_peer = GNUNET_YES; | ||
4659 | |||
4660 | if (GNUNET_YES == | ||
4661 | GNUNET_CONFIGURATION_get_value_yesno (cfg, "dht", "use_real_distance")) | ||
4662 | use_real_distance = GNUNET_YES; | ||
4663 | |||
4664 | if (GNUNET_YES == | ||
4665 | GNUNET_CONFIGURATION_get_value_yesno (cfg, "dht_testing", | ||
4666 | "mysql_logging_extended")) | ||
4667 | { | ||
4668 | debug_routes = GNUNET_YES; | ||
4669 | debug_routes_extended = GNUNET_YES; | ||
4670 | } | ||
4671 | |||
4672 | #if DEBUG_DHT_ROUTING | ||
4673 | if (GNUNET_YES == debug_routes) | ||
4674 | { | ||
4675 | dhtlog_handle = GNUNET_DHTLOG_connect (cfg); | ||
4676 | if (dhtlog_handle == NULL) | ||
4677 | { | ||
4678 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
4679 | "Could not connect to mysql logging server, logging will not happen!"); | ||
4680 | } | ||
4681 | } | ||
4682 | #endif | ||
4683 | |||
4684 | if (GNUNET_YES == | ||
4685 | GNUNET_CONFIGURATION_get_value_yesno (cfg, "dht", "paper_forwarding")) | ||
4686 | paper_forwarding = GNUNET_YES; | ||
4687 | |||
4688 | if (GNUNET_YES == | ||
4689 | GNUNET_CONFIGURATION_get_value_yesno (cfg, "dht", "put_peer_identities")) | ||
4690 | put_peer_identities = GNUNET_YES; | ||
4691 | |||
4692 | stats = GNUNET_STATISTICS_create ("dht", cfg); | ||
4693 | |||
4694 | if (stats != NULL) | ||
4695 | { | ||
4696 | GNUNET_STATISTICS_set (stats, STAT_ROUTES, 0, GNUNET_NO); | ||
4697 | GNUNET_STATISTICS_set (stats, STAT_ROUTE_FORWARDS, 0, GNUNET_NO); | ||
4698 | GNUNET_STATISTICS_set (stats, STAT_ROUTE_FORWARDS_CLOSEST, 0, GNUNET_NO); | ||
4699 | GNUNET_STATISTICS_set (stats, STAT_RESULTS, 0, GNUNET_NO); | ||
4700 | GNUNET_STATISTICS_set (stats, STAT_RESULTS_TO_CLIENT, 0, GNUNET_NO); | ||
4701 | GNUNET_STATISTICS_set (stats, STAT_RESULT_FORWARDS, 0, GNUNET_NO); | ||
4702 | GNUNET_STATISTICS_set (stats, STAT_GETS, 0, GNUNET_NO); | ||
4703 | GNUNET_STATISTICS_set (stats, STAT_PUTS, 0, GNUNET_NO); | ||
4704 | GNUNET_STATISTICS_set (stats, STAT_PUTS_INSERTED, 0, GNUNET_NO); | ||
4705 | GNUNET_STATISTICS_set (stats, STAT_FIND_PEER, 0, GNUNET_NO); | ||
4706 | GNUNET_STATISTICS_set (stats, STAT_FIND_PEER_START, 0, GNUNET_NO); | ||
4707 | GNUNET_STATISTICS_set (stats, STAT_GET_START, 0, GNUNET_NO); | ||
4708 | GNUNET_STATISTICS_set (stats, STAT_PUT_START, 0, GNUNET_NO); | ||
4709 | GNUNET_STATISTICS_set (stats, STAT_FIND_PEER_REPLY, 0, GNUNET_NO); | ||
4710 | GNUNET_STATISTICS_set (stats, STAT_FIND_PEER_ANSWER, 0, GNUNET_NO); | ||
4711 | GNUNET_STATISTICS_set (stats, STAT_BLOOM_FIND_PEER, 0, GNUNET_NO); | ||
4712 | GNUNET_STATISTICS_set (stats, STAT_GET_REPLY, 0, GNUNET_NO); | ||
4713 | GNUNET_STATISTICS_set (stats, STAT_GET_RESPONSE_START, 0, GNUNET_NO); | ||
4714 | GNUNET_STATISTICS_set (stats, STAT_HELLOS_PROVIDED, 0, GNUNET_NO); | ||
4715 | GNUNET_STATISTICS_set (stats, STAT_DISCONNECTS, 0, GNUNET_NO); | ||
4716 | } | ||
4717 | if (GNUNET_YES == do_find_peer) | ||
4718 | { | ||
4719 | next_send_time.rel_value = | ||
4720 | DHT_MINIMUM_FIND_PEER_INTERVAL.rel_value + | ||
4721 | GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, | ||
4722 | (DHT_MAXIMUM_FIND_PEER_INTERVAL.rel_value / | ||
4723 | 2) - | ||
4724 | DHT_MINIMUM_FIND_PEER_INTERVAL.rel_value); | ||
4725 | find_peer_context.start = GNUNET_TIME_absolute_get (); | ||
4726 | GNUNET_SCHEDULER_add_delayed (next_send_time, &send_find_peer_message, | ||
4727 | &find_peer_context); | ||
4728 | } | ||
4729 | |||
4730 | /* Scheduled the task to clean up when shutdown is called */ | ||
4731 | cleanup_task = | ||
4732 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, | ||
4733 | &shutdown_task, NULL); | ||
4734 | } | ||
4735 | |||
4736 | |||
4737 | /** | ||
4738 | * The main function for the dht service. | ||
4739 | * | ||
4740 | * @param argc number of arguments from the command line | ||
4741 | * @param argv command line arguments | ||
4742 | * @return 0 ok, 1 on error | ||
4743 | */ | ||
4744 | int | ||
4745 | main (int argc, char *const *argv) | ||
4746 | { | ||
4747 | int ret; | ||
4748 | |||
4749 | #if HAVE_UID_FOR_TESTING > 1 | ||
4750 | recent.hashmap = GNUNET_CONTAINER_multihashmap_create (DHT_MAX_RECENT / 2); | ||
4751 | #endif | ||
4752 | recent.minHeap = | ||
4753 | GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); | ||
4754 | recent_find_peer_requests = | ||
4755 | GNUNET_CONTAINER_multihashmap_create (MAX_BUCKETS / 8); | ||
4756 | ret = | ||
4757 | (GNUNET_OK == | ||
4758 | GNUNET_SERVICE_run (argc, argv, "dht", GNUNET_SERVICE_OPTION_NONE, &run, | ||
4759 | NULL)) ? 0 : 1; | ||
4760 | #if HAVE_UID_FOR_TESTING > 1 | ||
4761 | GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (recent.hashmap)); | ||
4762 | GNUNET_CONTAINER_multihashmap_destroy (recent.hashmap); | ||
4763 | recent.hashmap = NULL; | ||
4764 | #endif | ||
4765 | GNUNET_assert (0 == GNUNET_CONTAINER_heap_get_size (recent.minHeap)); | ||
4766 | GNUNET_CONTAINER_heap_destroy (recent.minHeap); | ||
4767 | recent.minHeap = NULL; | ||
4768 | GNUNET_CONTAINER_multihashmap_destroy (recent_find_peer_requests); | ||
4769 | recent_find_peer_requests = NULL; | ||
4770 | return ret; | ||
4771 | } | ||
4772 | |||
4773 | /* end of gnunet-service-dht.c */ | ||
diff --git a/src/dht/plugin_dhtlog_dummy.c b/src/dht/plugin_dhtlog_dummy.c deleted file mode 100644 index 563d97e46..000000000 --- a/src/dht/plugin_dhtlog_dummy.c +++ /dev/null | |||
@@ -1,347 +0,0 @@ | |||
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_dummy.c | ||
23 | * @brief Dummy logging plugin to test logging calls | ||
24 | * @author Nathan Evans | ||
25 | * | ||
26 | * Database: NONE | ||
27 | */ | ||
28 | |||
29 | #include "platform.h" | ||
30 | #include "gnunet_util_lib.h" | ||
31 | #include "dhtlog.h" | ||
32 | |||
33 | #define DEBUG_DHTLOG GNUNET_NO | ||
34 | |||
35 | /* | ||
36 | * Inserts the specified trial into the dhttests.trials table | ||
37 | * | ||
38 | * @param trial_info struct containing the data to insert about this trial | ||
39 | * | ||
40 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
41 | */ | ||
42 | int | ||
43 | add_trial (struct GNUNET_DHTLOG_TrialInfo *trial_info) | ||
44 | { | ||
45 | return GNUNET_OK; | ||
46 | } | ||
47 | |||
48 | /* | ||
49 | * Inserts the specified round into the dhttests.rounds table | ||
50 | * | ||
51 | * @param round_type the type of round that is being started | ||
52 | * @param round_count counter for the round (if applicable) | ||
53 | * | ||
54 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
55 | */ | ||
56 | int | ||
57 | add_round (unsigned int round_type, unsigned int round_count) | ||
58 | { | ||
59 | return GNUNET_OK; | ||
60 | } | ||
61 | |||
62 | /* | ||
63 | * Inserts the specified round results into the | ||
64 | * dhttests.processed_round_details table | ||
65 | * | ||
66 | * @param round_type the type of round that is being started | ||
67 | * @param round_count counter for the round (if applicable) | ||
68 | * @param num_messages the total number of messages initiated | ||
69 | * @param num_messages_succeeded the number of messages that succeeded | ||
70 | * | ||
71 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
72 | */ | ||
73 | int | ||
74 | add_round_details (unsigned int round_type, unsigned int round_count, | ||
75 | unsigned int num_messages, | ||
76 | unsigned int num_messages_succeded) | ||
77 | { | ||
78 | return GNUNET_OK; | ||
79 | } | ||
80 | |||
81 | /* | ||
82 | * Inserts the specified dhtkey into the dhttests.dhtkeys table, | ||
83 | * stores return value of dhttests.dhtkeys.dhtkeyuid into dhtkeyuid | ||
84 | * | ||
85 | * @param dhtkeyuid return value | ||
86 | * @param dhtkey hashcode of key to insert | ||
87 | * | ||
88 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
89 | */ | ||
90 | int | ||
91 | add_dhtkey (unsigned long long *dhtkeyuid, const GNUNET_HashCode * dhtkey) | ||
92 | { | ||
93 | *dhtkeyuid = 1171; | ||
94 | return GNUNET_OK; | ||
95 | } | ||
96 | |||
97 | |||
98 | /* | ||
99 | * Inserts the specified node into the dhttests.nodes table | ||
100 | * | ||
101 | * @param nodeuid the inserted node uid | ||
102 | * @param node the node to insert | ||
103 | * | ||
104 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
105 | */ | ||
106 | int | ||
107 | add_node (unsigned long long *nodeuid, struct GNUNET_PeerIdentity *node) | ||
108 | { | ||
109 | *nodeuid = 1337; | ||
110 | return GNUNET_OK; | ||
111 | } | ||
112 | |||
113 | /* | ||
114 | * Update dhttests.trials table with current server time as end time | ||
115 | * | ||
116 | * @param gets_succeeded how many gets did the testcase report as successful | ||
117 | * | ||
118 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure. | ||
119 | */ | ||
120 | int | ||
121 | update_trials (unsigned int gets_succeeded) | ||
122 | { | ||
123 | return GNUNET_OK; | ||
124 | } | ||
125 | |||
126 | |||
127 | /* | ||
128 | * Inserts the specified stats into the dhttests.generic_stats table | ||
129 | * | ||
130 | * @param peer the peer inserting the statistic | ||
131 | * @param name the name of the statistic | ||
132 | * @param section the section of the statistic | ||
133 | * @param value the value of the statistic | ||
134 | * | ||
135 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
136 | */ | ||
137 | int | ||
138 | add_generic_stat (const struct GNUNET_PeerIdentity *peer, const char *name, | ||
139 | const char *section, uint64_t value) | ||
140 | { | ||
141 | return GNUNET_OK; | ||
142 | } | ||
143 | |||
144 | /* | ||
145 | * Update dhttests.trials table with total connections information | ||
146 | * | ||
147 | * @param totalConnections the number of connections | ||
148 | * | ||
149 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure. | ||
150 | */ | ||
151 | int | ||
152 | add_connections (unsigned int totalConnections) | ||
153 | { | ||
154 | return GNUNET_OK; | ||
155 | } | ||
156 | |||
157 | /* | ||
158 | * Inserts the specified query into the dhttests.queries table | ||
159 | * | ||
160 | * @param sqlqueruid inserted query uid | ||
161 | * @param queryid dht query id | ||
162 | * @param type type of the query | ||
163 | * @param hops number of hops query traveled | ||
164 | * @param succeeded whether or not query was successful | ||
165 | * @param node the node the query hit | ||
166 | * @param key the key of the query | ||
167 | * | ||
168 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure. | ||
169 | */ | ||
170 | int | ||
171 | add_query (unsigned long long *sqlqueryuid, unsigned long long queryid, | ||
172 | unsigned int type, unsigned int hops, int succeeded, | ||
173 | const struct GNUNET_PeerIdentity *node, const GNUNET_HashCode * key) | ||
174 | { | ||
175 | *sqlqueryuid = 17; | ||
176 | return GNUNET_OK; | ||
177 | } | ||
178 | |||
179 | /* | ||
180 | * Inserts the specified route information into the dhttests.routes table | ||
181 | * | ||
182 | * @param sqlqueruid inserted query uid | ||
183 | * @param queryid dht query id | ||
184 | * @param type type of the query | ||
185 | * @param hops number of hops query traveled | ||
186 | * @param succeeded whether or not query was successful | ||
187 | * @param node the node the query hit | ||
188 | * @param key the key of the query | ||
189 | * @param from_node the node that sent the message to node | ||
190 | * @param to_node next node to forward message to | ||
191 | * | ||
192 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure. | ||
193 | */ | ||
194 | int | ||
195 | add_route (unsigned long long *sqlqueryuid, unsigned long long queryid, | ||
196 | unsigned int type, unsigned int hops, int succeeded, | ||
197 | const struct GNUNET_PeerIdentity *node, const GNUNET_HashCode * key, | ||
198 | const struct GNUNET_PeerIdentity *from_node, | ||
199 | const struct GNUNET_PeerIdentity *to_node) | ||
200 | { | ||
201 | *sqlqueryuid = 18; | ||
202 | return GNUNET_OK; | ||
203 | } | ||
204 | |||
205 | |||
206 | /* | ||
207 | * Records the current topology (number of connections, time, trial) | ||
208 | * | ||
209 | * @param num_connections how many connections are in the topology | ||
210 | * | ||
211 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
212 | */ | ||
213 | int | ||
214 | add_topology (int num_connections) | ||
215 | { | ||
216 | return GNUNET_OK; | ||
217 | } | ||
218 | |||
219 | /* | ||
220 | * Records a connection between two peers in the current topology | ||
221 | * | ||
222 | * @param first one side of the connection | ||
223 | * @param second other side of the connection | ||
224 | * | ||
225 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
226 | */ | ||
227 | int | ||
228 | add_extended_topology (const struct GNUNET_PeerIdentity *first, | ||
229 | const struct GNUNET_PeerIdentity *second) | ||
230 | { | ||
231 | return GNUNET_OK; | ||
232 | } | ||
233 | |||
234 | /* | ||
235 | * Update dhttests.topology table with total connections information | ||
236 | * | ||
237 | * @param totalConnections the number of connections | ||
238 | * | ||
239 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure. | ||
240 | */ | ||
241 | int | ||
242 | update_topology (unsigned int connections) | ||
243 | { | ||
244 | return GNUNET_OK; | ||
245 | } | ||
246 | |||
247 | /* | ||
248 | * Update dhttests.nodes table setting the identified | ||
249 | * node as a malicious dropper. | ||
250 | * | ||
251 | * @param peer the peer that was set to be malicious | ||
252 | * | ||
253 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure. | ||
254 | */ | ||
255 | int | ||
256 | set_malicious (struct GNUNET_PeerIdentity *peer) | ||
257 | { | ||
258 | return GNUNET_OK; | ||
259 | } | ||
260 | |||
261 | /* | ||
262 | * Inserts the specified stats into the dhttests.node_statistics table | ||
263 | * | ||
264 | * @param peer the peer inserting the statistic | ||
265 | * @param route_requests route requests seen | ||
266 | * @param route_forwards route requests forwarded | ||
267 | * @param result_requests route result requests seen | ||
268 | * @param client_requests client requests initiated | ||
269 | * @param result_forwards route results forwarded | ||
270 | * @param gets get requests handled | ||
271 | * @param puts put requests handle | ||
272 | * @param data_inserts data inserted at this node | ||
273 | * @param find_peer_requests find peer requests seen | ||
274 | * @param find_peers_started find peer requests initiated at this node | ||
275 | * @param gets_started get requests initiated at this node | ||
276 | * @param puts_started put requests initiated at this node | ||
277 | * @param find_peer_responses_received find peer responses received locally | ||
278 | * @param get_responses_received get responses received locally | ||
279 | * @param find_peer_responses_sent find peer responses sent from this node | ||
280 | * @param get_responses_sent get responses sent from this node | ||
281 | * | ||
282 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
283 | */ | ||
284 | int | ||
285 | insert_stat (const struct GNUNET_PeerIdentity *peer, | ||
286 | unsigned int route_requests, unsigned int route_forwards, | ||
287 | unsigned int result_requests, unsigned int client_requests, | ||
288 | unsigned int result_forwards, unsigned int gets, unsigned int puts, | ||
289 | unsigned int data_inserts, unsigned int find_peer_requests, | ||
290 | unsigned int find_peers_started, unsigned int gets_started, | ||
291 | unsigned int puts_started, | ||
292 | unsigned int find_peer_responses_received, | ||
293 | unsigned int get_responses_received, | ||
294 | unsigned int find_peer_responses_sent, | ||
295 | unsigned int get_responses_sent) | ||
296 | { | ||
297 | return GNUNET_OK; | ||
298 | } | ||
299 | |||
300 | /* | ||
301 | * Provides the dhtlog api | ||
302 | * | ||
303 | * @param c the configuration to use to connect to a server | ||
304 | * | ||
305 | * @return the handle to the server, or NULL on error | ||
306 | */ | ||
307 | void * | ||
308 | libgnunet_plugin_dhtlog_dummy_init (void *cls) | ||
309 | { | ||
310 | struct GNUNET_DHTLOG_Plugin *plugin = cls; | ||
311 | |||
312 | #if DEBUG_DHTLOG | ||
313 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "DUMMY DHT Logger: initializing.\n"); | ||
314 | #endif | ||
315 | GNUNET_assert (plugin->dhtlog_api == NULL); | ||
316 | plugin->dhtlog_api = GNUNET_malloc (sizeof (struct GNUNET_DHTLOG_Handle)); | ||
317 | plugin->dhtlog_api->add_generic_stat = &add_generic_stat; | ||
318 | plugin->dhtlog_api->insert_round = &add_round; | ||
319 | plugin->dhtlog_api->insert_round_details = &add_round_details; | ||
320 | plugin->dhtlog_api->insert_stat = &insert_stat; | ||
321 | plugin->dhtlog_api->insert_trial = &add_trial; | ||
322 | plugin->dhtlog_api->insert_query = &add_query; | ||
323 | plugin->dhtlog_api->update_trial = &update_trials; | ||
324 | plugin->dhtlog_api->set_malicious = &set_malicious; | ||
325 | plugin->dhtlog_api->insert_route = &add_route; | ||
326 | plugin->dhtlog_api->insert_node = &add_node; | ||
327 | plugin->dhtlog_api->insert_dhtkey = &add_dhtkey; | ||
328 | plugin->dhtlog_api->update_connections = &add_connections; | ||
329 | plugin->dhtlog_api->insert_topology = &add_topology; | ||
330 | plugin->dhtlog_api->update_topology = &update_topology; | ||
331 | plugin->dhtlog_api->insert_extended_topology = &add_extended_topology; | ||
332 | return plugin; | ||
333 | } | ||
334 | |||
335 | /** | ||
336 | * Shutdown the plugin. | ||
337 | */ | ||
338 | void * | ||
339 | libgnunet_plugin_dhtlog_dummy_done (void *cls) | ||
340 | { | ||
341 | #if DEBUG_DHTLOG | ||
342 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "DUMMY DHT Logger: shutdown\n"); | ||
343 | #endif | ||
344 | return NULL; | ||
345 | } | ||
346 | |||
347 | /* end of plugin_dhtlog_dummy.c */ | ||
diff --git a/src/dht/plugin_dhtlog_mysql.c b/src/dht/plugin_dhtlog_mysql.c deleted file mode 100644 index 33028fb09..000000000 --- a/src/dht/plugin_dhtlog_mysql.c +++ /dev/null | |||
@@ -1,1612 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2006 - 2009 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 2, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file src/dht/plugin_dhtlog_mysql.c | ||
23 | * @brief MySQL logging plugin to record DHT operations to MySQL server | ||
24 | * @author Nathan Evans | ||
25 | * | ||
26 | * Database: MySQL | ||
27 | */ | ||
28 | |||
29 | #include "platform.h" | ||
30 | #include "gnunet_util_lib.h" | ||
31 | #include "dhtlog.h" | ||
32 | #include <mysql/mysql.h> | ||
33 | |||
34 | |||
35 | #define DEBUG_DHTLOG GNUNET_YES | ||
36 | |||
37 | /** | ||
38 | * Maximum number of supported parameters for a prepared | ||
39 | * statement. Increase if needed. | ||
40 | */ | ||
41 | #define MAX_PARAM 32 | ||
42 | |||
43 | /** | ||
44 | * A generic statement handle to use | ||
45 | * for prepared statements. This way, | ||
46 | * once the statement is initialized | ||
47 | * we don't redo work. | ||
48 | */ | ||
49 | struct StatementHandle | ||
50 | { | ||
51 | /** | ||
52 | * Internal statement | ||
53 | */ | ||
54 | MYSQL_STMT *statement; | ||
55 | |||
56 | /** | ||
57 | * Textual query | ||
58 | */ | ||
59 | char *query; | ||
60 | |||
61 | /** | ||
62 | * Whether or not the handle is valid | ||
63 | */ | ||
64 | int valid; | ||
65 | }; | ||
66 | |||
67 | /** | ||
68 | * Type of a callback that will be called for each | ||
69 | * data set returned from MySQL. | ||
70 | * | ||
71 | * @param cls user-defined argument | ||
72 | * @param num_values number of elements in values | ||
73 | * @param values values returned by MySQL | ||
74 | * @return GNUNET_OK to continue iterating, GNUNET_SYSERR to abort | ||
75 | */ | ||
76 | typedef int (*GNUNET_MysqlDataProcessor) (void *cls, unsigned int num_values, | ||
77 | MYSQL_BIND * values); | ||
78 | |||
79 | static unsigned long max_varchar_len; | ||
80 | |||
81 | /** | ||
82 | * The configuration the DHT service is running with | ||
83 | */ | ||
84 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
85 | |||
86 | static unsigned long long current_trial = 0; /* I like to assign 0, just to remember */ | ||
87 | |||
88 | /** | ||
89 | * Connection to the MySQL Server. | ||
90 | */ | ||
91 | static MYSQL *conn; | ||
92 | |||
93 | #define INSERT_QUERIES_STMT "INSERT INTO queries (trialuid, querytype, hops, dhtkeyuid, dhtqueryid, succeeded, nodeuid, time) "\ | ||
94 | "VALUES (?, ?, ?, ?, ?, ?, ?, NOW())" | ||
95 | static struct StatementHandle *insert_query; | ||
96 | |||
97 | #define INSERT_ROUTES_STMT "INSERT INTO routes (trialuid, querytype, hops, dhtkeyuid, dhtqueryid, succeeded, nodeuid, from_node, to_node) "\ | ||
98 | "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)" | ||
99 | static struct StatementHandle *insert_route; | ||
100 | |||
101 | #define INSERT_NODES_STMT "INSERT INTO nodes (trialuid, nodeid, nodebits) "\ | ||
102 | "VALUES (?, ?, ?)" | ||
103 | static struct StatementHandle *insert_node; | ||
104 | |||
105 | #define INSERT_ROUNDS_STMT "INSERT INTO rounds (trialuid, round_type, round_count, starttime) "\ | ||
106 | "VALUES (?, ?, ?, NOW())" | ||
107 | |||
108 | static struct StatementHandle *insert_round; | ||
109 | |||
110 | #define INSERT_ROUND_DETAILS_STMT "INSERT INTO rounds (trialuid, round_type, round_count, starttime, endtime, num_messages, num_messages_succeeded) "\ | ||
111 | "VALUES (?, ?, ?, NOW(), NOW(), ?, ?)" | ||
112 | |||
113 | static struct StatementHandle *insert_round_details; | ||
114 | |||
115 | #define INSERT_TRIALS_STMT "INSERT INTO trials"\ | ||
116 | "(starttime, other_trial_identifier, numnodes, topology,"\ | ||
117 | "topology_percentage, topology_probability,"\ | ||
118 | "blacklist_topology, connect_topology, connect_topology_option,"\ | ||
119 | "connect_topology_option_modifier, puts, gets, "\ | ||
120 | "concurrent, settle_time, num_rounds, malicious_getters,"\ | ||
121 | "malicious_putters, malicious_droppers, malicious_get_frequency,"\ | ||
122 | "malicious_put_frequency, stop_closest, stop_found, strict_kademlia, "\ | ||
123 | "gets_succeeded, message) "\ | ||
124 | "VALUES (NOW(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" | ||
125 | |||
126 | static struct StatementHandle *insert_trial; | ||
127 | |||
128 | #define INSERT_STAT_STMT "INSERT INTO node_statistics"\ | ||
129 | "(trialuid, nodeuid, route_requests,"\ | ||
130 | "route_forwards, result_requests,"\ | ||
131 | "client_results, result_forwards, gets,"\ | ||
132 | "puts, data_inserts, find_peer_requests, "\ | ||
133 | "find_peers_started, gets_started, puts_started, find_peer_responses_received,"\ | ||
134 | "get_responses_received, find_peer_responses_sent, get_responses_sent) "\ | ||
135 | "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" | ||
136 | |||
137 | static struct StatementHandle *insert_stat; | ||
138 | |||
139 | #define INSERT_GENERIC_STAT_STMT "INSERT INTO generic_stats" \ | ||
140 | "(trialuid, nodeuid, section, name, value)"\ | ||
141 | "VALUES (?, ?, ?, ?, ?)" | ||
142 | static struct StatementHandle *insert_generic_stat; | ||
143 | |||
144 | #define INSERT_DHTKEY_STMT "INSERT INTO dhtkeys (dhtkey, trialuid, keybits) "\ | ||
145 | "VALUES (?, ?, ?)" | ||
146 | static struct StatementHandle *insert_dhtkey; | ||
147 | |||
148 | #define UPDATE_TRIALS_STMT "UPDATE trials set endtime=NOW(), gets_succeeded = ? where trialuid = ?" | ||
149 | static struct StatementHandle *update_trial; | ||
150 | |||
151 | #define UPDATE_CONNECTIONS_STMT "UPDATE trials set totalConnections = ? where trialuid = ?" | ||
152 | static struct StatementHandle *update_connection; | ||
153 | |||
154 | #define GET_TRIAL_STMT "SELECT MAX( trialuid ) FROM trials" | ||
155 | static struct StatementHandle *get_trial; | ||
156 | |||
157 | #define GET_TOPOLOGY_STMT "SELECT MAX( topology_uid ) FROM topology" | ||
158 | static struct StatementHandle *get_topology; | ||
159 | |||
160 | #define GET_DHTKEYUID_STMT "SELECT dhtkeyuid FROM dhtkeys where dhtkey = ? and trialuid = ?" | ||
161 | static struct StatementHandle *get_dhtkeyuid; | ||
162 | |||
163 | #define GET_NODEUID_STMT "SELECT nodeuid FROM nodes where trialuid = ? and nodeid = ?" | ||
164 | static struct StatementHandle *get_nodeuid; | ||
165 | |||
166 | #define INSERT_TOPOLOGY_STMT "INSERT INTO topology (trialuid, date, connections) "\ | ||
167 | "VALUES (?, NOW(), ?)" | ||
168 | static struct StatementHandle *insert_topology; | ||
169 | |||
170 | #define EXTEND_TOPOLOGY_STMT "INSERT INTO extended_topology (topology_uid, uid_first, uid_second) "\ | ||
171 | "VALUES (?, ?, ?)" | ||
172 | static struct StatementHandle *extend_topology; | ||
173 | |||
174 | #define SET_MALICIOUS_STMT "update nodes set malicious_dropper = 1 where trialuid = ? and nodeid = ?" | ||
175 | static struct StatementHandle *update_node_malicious; | ||
176 | |||
177 | #define UPDATE_TOPOLOGY_STMT "update topology set connections = ? where topology_uid = ?" | ||
178 | static struct StatementHandle *update_topology; | ||
179 | |||
180 | /** | ||
181 | * Run a query (not a select statement) | ||
182 | * | ||
183 | * @return GNUNET_OK if executed, GNUNET_SYSERR if an error occurred | ||
184 | */ | ||
185 | int | ||
186 | run_statement (const char *statement) | ||
187 | { | ||
188 | mysql_query (conn, statement); | ||
189 | if (mysql_error (conn)[0]) | ||
190 | { | ||
191 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "mysql_query"); | ||
192 | return GNUNET_SYSERR; | ||
193 | } | ||
194 | return GNUNET_OK; | ||
195 | } | ||
196 | |||
197 | /* | ||
198 | * Creates tables if they don't already exist for dht logging | ||
199 | */ | ||
200 | static int | ||
201 | itable () | ||
202 | { | ||
203 | #define MRUNS(a) (GNUNET_OK != run_statement (a) ) | ||
204 | |||
205 | if (MRUNS | ||
206 | ("CREATE TABLE IF NOT EXISTS `dhtkeys` (" | ||
207 | "dhtkeyuid int(10) unsigned NOT NULL auto_increment COMMENT 'Unique Key given to each query'," | ||
208 | "`dhtkey` varchar(255) NOT NULL COMMENT 'The ASCII value of the key being searched for'," | ||
209 | "trialuid int(10) unsigned NOT NULL," "keybits blob NOT NULL," | ||
210 | "UNIQUE KEY `dhtkeyuid` (`dhtkeyuid`)" | ||
211 | ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1")) | ||
212 | return GNUNET_SYSERR; | ||
213 | |||
214 | if (MRUNS | ||
215 | ("CREATE TABLE IF NOT EXISTS `nodes` (" | ||
216 | "`nodeuid` int(10) unsigned NOT NULL auto_increment," | ||
217 | "`trialuid` int(10) unsigned NOT NULL," "`nodeid` varchar(255) NOT NULL," | ||
218 | "`nodebits` blob NOT NULL," "PRIMARY KEY (`nodeuid`)" | ||
219 | ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1")) | ||
220 | return GNUNET_SYSERR; | ||
221 | |||
222 | if (MRUNS | ||
223 | ("CREATE TABLE IF NOT EXISTS `queries` (" | ||
224 | "`trialuid` int(10) unsigned NOT NULL," | ||
225 | "`queryuid` int(10) unsigned NOT NULL auto_increment," | ||
226 | "`dhtqueryid` bigint(20) NOT NULL," | ||
227 | "`querytype` enum('1','2','3','4','5') NOT NULL," | ||
228 | "`hops` int(10) unsigned NOT NULL," "`succeeded` tinyint NOT NULL," | ||
229 | "`nodeuid` int(10) unsigned NOT NULL," | ||
230 | "`time` timestamp NOT NULL default CURRENT_TIMESTAMP," | ||
231 | "`dhtkeyuid` int(10) unsigned NOT NULL," "PRIMARY KEY (`queryuid`)" | ||
232 | ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1")) | ||
233 | return GNUNET_SYSERR; | ||
234 | |||
235 | if (MRUNS | ||
236 | ("CREATE TABLE IF NOT EXISTS `routes` (" | ||
237 | "`trialuid` int(10) unsigned NOT NULL," | ||
238 | "`queryuid` int(10) unsigned NOT NULL auto_increment," | ||
239 | "`dhtqueryid` bigint(20) NOT NULL," | ||
240 | "`querytype` enum('1','2','3','4','5') NOT NULL," | ||
241 | "`hops` int(10) unsigned NOT NULL," "`succeeded` tinyint NOT NULL," | ||
242 | "`nodeuid` int(10) unsigned NOT NULL," | ||
243 | "`time` timestamp NOT NULL default CURRENT_TIMESTAMP," | ||
244 | "`dhtkeyuid` int(10) unsigned NOT NULL," | ||
245 | "`from_node` int(10) unsigned NOT NULL," | ||
246 | "`to_node` int(10) unsigned NOT NULL," "PRIMARY KEY (`queryuid`)" | ||
247 | ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1")) | ||
248 | return GNUNET_SYSERR; | ||
249 | |||
250 | if (MRUNS | ||
251 | ("CREATE TABLE IF NOT EXISTS `trials` (" | ||
252 | "`trialuid` int(10) unsigned NOT NULL auto_increment," | ||
253 | "`other_trial_identifier` int(10) unsigned NOT NULL default '0'," | ||
254 | "`numnodes` int(10) unsigned NOT NULL," "`topology` int(10) NOT NULL," | ||
255 | "`blacklist_topology` int(11) NOT NULL," | ||
256 | "`connect_topology` int(11) NOT NULL," | ||
257 | "`connect_topology_option` int(11) NOT NULL," | ||
258 | "`topology_percentage` float NOT NULL," | ||
259 | "`topology_probability` float NOT NULL," | ||
260 | "`connect_topology_option_modifier` float NOT NULL," | ||
261 | "`starttime` datetime NOT NULL," "`endtime` datetime NOT NULL," | ||
262 | "`puts` int(10) unsigned NOT NULL," "`gets` int(10) unsigned NOT NULL," | ||
263 | "`concurrent` int(10) unsigned NOT NULL," | ||
264 | "`settle_time` int(10) unsigned NOT NULL," | ||
265 | "`totalConnections` int(10) unsigned NOT NULL," | ||
266 | "`message` text NOT NULL," "`num_rounds` int(10) unsigned NOT NULL," | ||
267 | "`malicious_getters` int(10) unsigned NOT NULL," | ||
268 | "`malicious_putters` int(10) unsigned NOT NULL," | ||
269 | "`malicious_droppers` int(10) unsigned NOT NULL," | ||
270 | "`topology_modifier` double NOT NULL," | ||
271 | "`malicious_get_frequency` int(10) unsigned NOT NULL," | ||
272 | "`malicious_put_frequency` int(10) unsigned NOT NULL," | ||
273 | "`stop_closest` int(10) unsigned NOT NULL," | ||
274 | "`stop_found` int(10) unsigned NOT NULL," | ||
275 | "`strict_kademlia` int(10) unsigned NOT NULL," | ||
276 | "`gets_succeeded` int(10) unsigned NOT NULL," | ||
277 | "PRIMARY KEY (`trialuid`)," "UNIQUE KEY `trialuid` (`trialuid`)" | ||
278 | ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1")) | ||
279 | return GNUNET_SYSERR; | ||
280 | |||
281 | if (MRUNS | ||
282 | ("CREATE TABLE IF NOT EXISTS `topology` (" | ||
283 | "`topology_uid` int(10) unsigned NOT NULL AUTO_INCREMENT," | ||
284 | "`trialuid` int(10) unsigned NOT NULL," "`date` datetime NOT NULL," | ||
285 | "`connections` int(10) unsigned NOT NULL," | ||
286 | "PRIMARY KEY (`topology_uid`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1")) | ||
287 | return GNUNET_SYSERR; | ||
288 | |||
289 | if (MRUNS | ||
290 | ("CREATE TABLE IF NOT EXISTS `extended_topology` (" | ||
291 | "`extended_uid` int(10) unsigned NOT NULL AUTO_INCREMENT," | ||
292 | "`topology_uid` int(10) unsigned NOT NULL," | ||
293 | "`uid_first` int(10) unsigned NOT NULL," | ||
294 | "`uid_second` int(10) unsigned NOT NULL," "PRIMARY KEY (`extended_uid`)" | ||
295 | ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1")) | ||
296 | return GNUNET_SYSERR; | ||
297 | |||
298 | if (MRUNS | ||
299 | ("CREATE TABLE IF NOT EXISTS `node_statistics` (" | ||
300 | "`stat_uid` int(10) unsigned NOT NULL AUTO_INCREMENT," | ||
301 | "`trialuid` int(10) unsigned NOT NULL," | ||
302 | "`nodeuid` int(10) unsigned NOT NULL," | ||
303 | "`route_requests` int(10) unsigned NOT NULL," | ||
304 | "`route_forwards` int(10) unsigned NOT NULL," | ||
305 | "`result_requests` int(10) unsigned NOT NULL," | ||
306 | "`client_results` int(10) unsigned NOT NULL," | ||
307 | "`result_forwards` int(10) unsigned NOT NULL," | ||
308 | "`gets` int(10) unsigned NOT NULL," "`puts` int(10) unsigned NOT NULL," | ||
309 | "`data_inserts` int(10) unsigned NOT NULL," | ||
310 | "`find_peer_requests` int(10) unsigned NOT NULL," | ||
311 | "`find_peers_started` int(10) unsigned NOT NULL," | ||
312 | "`gets_started` int(10) unsigned NOT NULL," | ||
313 | "`puts_started` int(10) unsigned NOT NULL," | ||
314 | "`find_peer_responses_received` int(10) unsigned NOT NULL," | ||
315 | "`get_responses_received` int(10) unsigned NOT NULL," | ||
316 | "`find_peer_responses_sent` int(10) unsigned NOT NULL," | ||
317 | "`get_responses_sent` int(10) unsigned NOT NULL," | ||
318 | "PRIMARY KEY (`stat_uid`)" | ||
319 | ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;")) | ||
320 | return GNUNET_SYSERR; | ||
321 | |||
322 | if (MRUNS ("SET AUTOCOMMIT = 1")) | ||
323 | return GNUNET_SYSERR; | ||
324 | |||
325 | return GNUNET_OK; | ||
326 | #undef MRUNS | ||
327 | } | ||
328 | |||
329 | /** | ||
330 | * Create a prepared statement. | ||
331 | * | ||
332 | * @return NULL on error | ||
333 | */ | ||
334 | struct StatementHandle * | ||
335 | prepared_statement_create (const char *statement) | ||
336 | { | ||
337 | struct StatementHandle *ret; | ||
338 | |||
339 | ret = GNUNET_malloc (sizeof (struct StatementHandle)); | ||
340 | ret->query = GNUNET_strdup (statement); | ||
341 | return ret; | ||
342 | } | ||
343 | |||
344 | /** | ||
345 | * Close a prepared statement. | ||
346 | * | ||
347 | * @return NULL on error | ||
348 | */ | ||
349 | void | ||
350 | prepared_statement_close (struct StatementHandle *s) | ||
351 | { | ||
352 | if (s == NULL) | ||
353 | { | ||
354 | return; | ||
355 | } | ||
356 | |||
357 | GNUNET_free_non_null (s->query); | ||
358 | |||
359 | if (s->valid == GNUNET_YES) | ||
360 | mysql_stmt_close (s->statement); | ||
361 | GNUNET_free (s); | ||
362 | } | ||
363 | |||
364 | /* | ||
365 | * Initialize the prepared statements for use with dht test logging | ||
366 | */ | ||
367 | static int | ||
368 | iopen (struct GNUNET_DHTLOG_Plugin *plugin) | ||
369 | { | ||
370 | int ret; | ||
371 | my_bool reconnect; | ||
372 | unsigned int timeout; | ||
373 | char *user; | ||
374 | char *password; | ||
375 | char *server; | ||
376 | char *database; | ||
377 | unsigned long long port; | ||
378 | |||
379 | conn = mysql_init (NULL); | ||
380 | if (conn == NULL) | ||
381 | return GNUNET_SYSERR; | ||
382 | |||
383 | if (GNUNET_OK != | ||
384 | GNUNET_CONFIGURATION_get_value_string (plugin->cfg, "MYSQL", "DATABASE", | ||
385 | &database)) | ||
386 | { | ||
387 | database = GNUNET_strdup ("gnunet"); | ||
388 | } | ||
389 | |||
390 | if (GNUNET_OK != | ||
391 | GNUNET_CONFIGURATION_get_value_string (plugin->cfg, "MYSQL", "USER", | ||
392 | &user)) | ||
393 | { | ||
394 | user = GNUNET_strdup ("dht"); | ||
395 | } | ||
396 | |||
397 | if (GNUNET_OK != | ||
398 | GNUNET_CONFIGURATION_get_value_string (plugin->cfg, "MYSQL", "PASSWORD", | ||
399 | &password)) | ||
400 | { | ||
401 | password = GNUNET_strdup ("dhttest**"); | ||
402 | } | ||
403 | |||
404 | if (GNUNET_OK != | ||
405 | GNUNET_CONFIGURATION_get_value_string (plugin->cfg, "MYSQL", "SERVER", | ||
406 | &server)) | ||
407 | { | ||
408 | server = GNUNET_strdup ("localhost"); | ||
409 | } | ||
410 | |||
411 | if (GNUNET_OK != | ||
412 | GNUNET_CONFIGURATION_get_value_number (plugin->cfg, "MYSQL", "MYSQL_PORT", | ||
413 | &port)) | ||
414 | { | ||
415 | port = 0; | ||
416 | } | ||
417 | |||
418 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
419 | "Connecting to mysql with: user %s, pass %s, server %s, database %s, port %d\n", | ||
420 | user, password, server, database, port); | ||
421 | |||
422 | reconnect = 0; | ||
423 | timeout = 60; /* in seconds */ | ||
424 | mysql_options (conn, MYSQL_OPT_RECONNECT, &reconnect); | ||
425 | mysql_options (conn, MYSQL_OPT_CONNECT_TIMEOUT, (const void *) &timeout); | ||
426 | mysql_options (conn, MYSQL_SET_CHARSET_NAME, "UTF8"); | ||
427 | mysql_options (conn, MYSQL_OPT_READ_TIMEOUT, (const void *) &timeout); | ||
428 | mysql_options (conn, MYSQL_OPT_WRITE_TIMEOUT, (const void *) &timeout); | ||
429 | mysql_real_connect (conn, server, user, password, database, | ||
430 | (unsigned int) port, NULL, CLIENT_IGNORE_SIGPIPE); | ||
431 | |||
432 | GNUNET_free_non_null (server); | ||
433 | GNUNET_free_non_null (password); | ||
434 | GNUNET_free_non_null (user); | ||
435 | GNUNET_free_non_null (database); | ||
436 | |||
437 | if (mysql_error (conn)[0]) | ||
438 | { | ||
439 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "mysql_real_connect"); | ||
440 | return GNUNET_SYSERR; | ||
441 | } | ||
442 | |||
443 | #if OLD | ||
444 | db = GNUNET_MYSQL_database_open (coreAPI->ectx, coreAPI->cfg); | ||
445 | if (db == NULL) | ||
446 | return GNUNET_SYSERR; | ||
447 | #endif | ||
448 | |||
449 | ret = itable (); | ||
450 | |||
451 | #define PINIT(a,b) (NULL == (a = prepared_statement_create(b))) | ||
452 | if (PINIT (insert_query, INSERT_QUERIES_STMT) || | ||
453 | PINIT (insert_route, INSERT_ROUTES_STMT) || | ||
454 | PINIT (insert_trial, INSERT_TRIALS_STMT) || | ||
455 | PINIT (insert_round, INSERT_ROUNDS_STMT) || | ||
456 | PINIT (insert_round_details, INSERT_ROUND_DETAILS_STMT) || | ||
457 | PINIT (insert_stat, INSERT_STAT_STMT) || | ||
458 | PINIT (insert_generic_stat, INSERT_GENERIC_STAT_STMT) || | ||
459 | PINIT (insert_node, INSERT_NODES_STMT) || | ||
460 | PINIT (insert_dhtkey, INSERT_DHTKEY_STMT) || | ||
461 | PINIT (update_trial, UPDATE_TRIALS_STMT) || | ||
462 | PINIT (get_dhtkeyuid, GET_DHTKEYUID_STMT) || | ||
463 | PINIT (get_nodeuid, GET_NODEUID_STMT) || | ||
464 | PINIT (update_connection, UPDATE_CONNECTIONS_STMT) || | ||
465 | PINIT (get_trial, GET_TRIAL_STMT) || | ||
466 | PINIT (get_topology, GET_TOPOLOGY_STMT) || | ||
467 | PINIT (insert_topology, INSERT_TOPOLOGY_STMT) || | ||
468 | PINIT (update_topology, UPDATE_TOPOLOGY_STMT) || | ||
469 | PINIT (extend_topology, EXTEND_TOPOLOGY_STMT) || | ||
470 | PINIT (update_node_malicious, SET_MALICIOUS_STMT)) | ||
471 | { | ||
472 | return GNUNET_SYSERR; | ||
473 | } | ||
474 | #undef PINIT | ||
475 | |||
476 | return ret; | ||
477 | } | ||
478 | |||
479 | static int | ||
480 | return_ok (void *cls, unsigned int num_values, MYSQL_BIND * values) | ||
481 | { | ||
482 | return GNUNET_OK; | ||
483 | } | ||
484 | |||
485 | /** | ||
486 | * Prepare a statement for running. | ||
487 | * | ||
488 | * @return GNUNET_OK on success | ||
489 | */ | ||
490 | static int | ||
491 | prepare_statement (struct StatementHandle *ret) | ||
492 | { | ||
493 | if (GNUNET_YES == ret->valid) | ||
494 | return GNUNET_OK; | ||
495 | |||
496 | ret->statement = mysql_stmt_init (conn); | ||
497 | if (ret->statement == NULL) | ||
498 | return GNUNET_SYSERR; | ||
499 | |||
500 | if (mysql_stmt_prepare (ret->statement, ret->query, strlen (ret->query))) | ||
501 | { | ||
502 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "mysql_stmt_prepare `%s', %s", | ||
503 | ret->query, mysql_error (conn)); | ||
504 | mysql_stmt_close (ret->statement); | ||
505 | ret->statement = NULL; | ||
506 | return GNUNET_SYSERR; | ||
507 | } | ||
508 | ret->valid = GNUNET_YES; | ||
509 | return GNUNET_OK; | ||
510 | } | ||
511 | |||
512 | /** | ||
513 | * Bind the parameters for the given MySQL statement | ||
514 | * and run it. | ||
515 | * | ||
516 | * @param s statement to bind and run | ||
517 | * @param ap arguments for the binding | ||
518 | * @return GNUNET_SYSERR on error, GNUNET_OK on success | ||
519 | */ | ||
520 | static int | ||
521 | init_params (struct StatementHandle *s, va_list ap) | ||
522 | { | ||
523 | MYSQL_BIND qbind[MAX_PARAM]; | ||
524 | unsigned int pc; | ||
525 | unsigned int off; | ||
526 | enum enum_field_types ft; | ||
527 | |||
528 | pc = mysql_stmt_param_count (s->statement); | ||
529 | if (pc > MAX_PARAM) | ||
530 | { | ||
531 | /* increase internal constant! */ | ||
532 | GNUNET_break (0); | ||
533 | return GNUNET_SYSERR; | ||
534 | } | ||
535 | memset (qbind, 0, sizeof (qbind)); | ||
536 | off = 0; | ||
537 | ft = 0; | ||
538 | while ((pc > 0) && (-1 != (ft = va_arg (ap, enum enum_field_types)))) | ||
539 | { | ||
540 | qbind[off].buffer_type = ft; | ||
541 | switch (ft) | ||
542 | { | ||
543 | case MYSQL_TYPE_FLOAT: | ||
544 | qbind[off].buffer = va_arg (ap, float *); | ||
545 | |||
546 | break; | ||
547 | case MYSQL_TYPE_LONGLONG: | ||
548 | qbind[off].buffer = va_arg (ap, unsigned long long *); | ||
549 | qbind[off].is_unsigned = va_arg (ap, int); | ||
550 | |||
551 | break; | ||
552 | case MYSQL_TYPE_LONG: | ||
553 | qbind[off].buffer = va_arg (ap, unsigned int *); | ||
554 | qbind[off].is_unsigned = va_arg (ap, int); | ||
555 | |||
556 | break; | ||
557 | case MYSQL_TYPE_VAR_STRING: | ||
558 | case MYSQL_TYPE_STRING: | ||
559 | case MYSQL_TYPE_BLOB: | ||
560 | qbind[off].buffer = va_arg (ap, void *); | ||
561 | qbind[off].buffer_length = va_arg (ap, unsigned long); | ||
562 | qbind[off].length = va_arg (ap, unsigned long *); | ||
563 | |||
564 | break; | ||
565 | default: | ||
566 | /* unsupported type */ | ||
567 | GNUNET_break (0); | ||
568 | return GNUNET_SYSERR; | ||
569 | } | ||
570 | pc--; | ||
571 | off++; | ||
572 | } | ||
573 | if (!((pc == 0) && (ft != -1) && (va_arg (ap, int) == -1))) | ||
574 | { | ||
575 | GNUNET_break (0); | ||
576 | return GNUNET_SYSERR; | ||
577 | } | ||
578 | if (mysql_stmt_bind_param (s->statement, qbind)) | ||
579 | { | ||
580 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
581 | _("`%s' failed at %s:%d with error: %s\n"), | ||
582 | "mysql_stmt_bind_param", __FILE__, __LINE__, | ||
583 | mysql_stmt_error (s->statement)); | ||
584 | return GNUNET_SYSERR; | ||
585 | } | ||
586 | |||
587 | if (mysql_stmt_execute (s->statement)) | ||
588 | { | ||
589 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
590 | _("`%s' failed at %s:%d with error: %s\n"), | ||
591 | "mysql_stmt_execute", __FILE__, __LINE__, | ||
592 | mysql_stmt_error (s->statement)); | ||
593 | return GNUNET_SYSERR; | ||
594 | } | ||
595 | |||
596 | return GNUNET_OK; | ||
597 | } | ||
598 | |||
599 | /** | ||
600 | * Run a prepared SELECT statement. | ||
601 | * | ||
602 | * @param s handle to the statement we should execute | ||
603 | * @param result_size number of results in set | ||
604 | * @param results pointer to already initialized MYSQL_BIND | ||
605 | * array (of sufficient size) for passing results | ||
606 | * @param processor function to call on each result | ||
607 | * @param processor_cls extra argument to processor | ||
608 | * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective | ||
609 | * values (size + buffer-reference for pointers); terminated | ||
610 | * with "-1" | ||
611 | * | ||
612 | * @return GNUNET_SYSERR on error, otherwise | ||
613 | * the number of successfully affected (or queried) rows | ||
614 | */ | ||
615 | int | ||
616 | prepared_statement_run_select (struct StatementHandle *s, | ||
617 | unsigned int result_size, MYSQL_BIND * results, | ||
618 | GNUNET_MysqlDataProcessor processor, | ||
619 | void *processor_cls, ...) | ||
620 | { | ||
621 | va_list ap; | ||
622 | int ret; | ||
623 | unsigned int rsize; | ||
624 | int total; | ||
625 | |||
626 | if (GNUNET_OK != prepare_statement (s)) | ||
627 | { | ||
628 | GNUNET_break (0); | ||
629 | return GNUNET_SYSERR; | ||
630 | } | ||
631 | va_start (ap, processor_cls); | ||
632 | if (GNUNET_OK != init_params (s, ap)) | ||
633 | { | ||
634 | GNUNET_break (0); | ||
635 | va_end (ap); | ||
636 | return GNUNET_SYSERR; | ||
637 | } | ||
638 | va_end (ap); | ||
639 | rsize = mysql_stmt_field_count (s->statement); | ||
640 | if (rsize > result_size) | ||
641 | { | ||
642 | GNUNET_break (0); | ||
643 | return GNUNET_SYSERR; | ||
644 | } | ||
645 | if (mysql_stmt_bind_result (s->statement, results)) | ||
646 | { | ||
647 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
648 | _("`%s' failed at %s:%d with error: %s\n"), | ||
649 | "mysql_stmt_bind_result", __FILE__, __LINE__, | ||
650 | mysql_stmt_error (s->statement)); | ||
651 | return GNUNET_SYSERR; | ||
652 | } | ||
653 | |||
654 | total = 0; | ||
655 | while (1) | ||
656 | { | ||
657 | ret = mysql_stmt_fetch (s->statement); | ||
658 | if (ret == MYSQL_NO_DATA) | ||
659 | break; | ||
660 | if (ret != 0) | ||
661 | { | ||
662 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
663 | _("`%s' failed at %s:%d with error: %s\n"), | ||
664 | "mysql_stmt_fetch", __FILE__, __LINE__, | ||
665 | mysql_stmt_error (s->statement)); | ||
666 | return GNUNET_SYSERR; | ||
667 | } | ||
668 | if (processor != NULL) | ||
669 | if (GNUNET_OK != processor (processor_cls, rsize, results)) | ||
670 | break; | ||
671 | total++; | ||
672 | } | ||
673 | mysql_stmt_reset (s->statement); | ||
674 | return total; | ||
675 | } | ||
676 | |||
677 | |||
678 | static int | ||
679 | get_node_uid (unsigned long long *nodeuid, const GNUNET_HashCode * peerHash) | ||
680 | { | ||
681 | MYSQL_BIND rbind[1]; | ||
682 | struct GNUNET_CRYPTO_HashAsciiEncoded encPeer; | ||
683 | unsigned long long p_len; | ||
684 | |||
685 | memset (rbind, 0, sizeof (rbind)); | ||
686 | rbind[0].buffer_type = MYSQL_TYPE_LONGLONG; | ||
687 | rbind[0].buffer = nodeuid; | ||
688 | rbind[0].is_unsigned = GNUNET_YES; | ||
689 | |||
690 | GNUNET_CRYPTO_hash_to_enc (peerHash, &encPeer); | ||
691 | p_len = strlen ((char *) &encPeer); | ||
692 | |||
693 | if (1 != | ||
694 | prepared_statement_run_select (get_nodeuid, 1, rbind, return_ok, NULL, | ||
695 | MYSQL_TYPE_LONGLONG, ¤t_trial, | ||
696 | GNUNET_YES, MYSQL_TYPE_VAR_STRING, | ||
697 | &encPeer, max_varchar_len, &p_len, -1)) | ||
698 | { | ||
699 | #if DEBUG_DHTLOG | ||
700 | fprintf (stderr, "FAILED\n"); | ||
701 | #endif | ||
702 | return GNUNET_SYSERR; | ||
703 | } | ||
704 | return GNUNET_OK; | ||
705 | } | ||
706 | |||
707 | static int | ||
708 | get_current_trial (unsigned long long *trialuid) | ||
709 | { | ||
710 | MYSQL_BIND rbind[1]; | ||
711 | |||
712 | memset (rbind, 0, sizeof (rbind)); | ||
713 | rbind[0].buffer_type = MYSQL_TYPE_LONG; | ||
714 | rbind[0].is_unsigned = 1; | ||
715 | rbind[0].buffer = trialuid; | ||
716 | |||
717 | if ((GNUNET_OK != | ||
718 | prepared_statement_run_select (get_trial, 1, rbind, return_ok, NULL, | ||
719 | -1))) | ||
720 | { | ||
721 | return GNUNET_SYSERR; | ||
722 | } | ||
723 | |||
724 | return GNUNET_OK; | ||
725 | } | ||
726 | |||
727 | static int | ||
728 | get_current_topology (unsigned long long *topologyuid) | ||
729 | { | ||
730 | MYSQL_BIND rbind[1]; | ||
731 | |||
732 | memset (rbind, 0, sizeof (rbind)); | ||
733 | rbind[0].buffer_type = MYSQL_TYPE_LONGLONG; | ||
734 | rbind[0].is_unsigned = 1; | ||
735 | rbind[0].buffer = topologyuid; | ||
736 | |||
737 | if ((GNUNET_OK != | ||
738 | prepared_statement_run_select (get_topology, 1, rbind, return_ok, NULL, | ||
739 | -1))) | ||
740 | { | ||
741 | return GNUNET_SYSERR; | ||
742 | } | ||
743 | |||
744 | return GNUNET_OK; | ||
745 | } | ||
746 | |||
747 | static int | ||
748 | get_dhtkey_uid (unsigned long long *dhtkeyuid, const GNUNET_HashCode * key) | ||
749 | { | ||
750 | MYSQL_BIND rbind[1]; | ||
751 | struct GNUNET_CRYPTO_HashAsciiEncoded encKey; | ||
752 | unsigned long long k_len; | ||
753 | |||
754 | memset (rbind, 0, sizeof (rbind)); | ||
755 | rbind[0].buffer_type = MYSQL_TYPE_LONG; | ||
756 | rbind[0].is_unsigned = 1; | ||
757 | rbind[0].buffer = dhtkeyuid; | ||
758 | GNUNET_CRYPTO_hash_to_enc (key, &encKey); | ||
759 | k_len = strlen ((char *) &encKey); | ||
760 | #if DEBUG_DHTLOG | ||
761 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
762 | "Searching for dhtkey `%s' in trial %llu\n", GNUNET_h2s (key), | ||
763 | current_trial); | ||
764 | #endif | ||
765 | if ((GNUNET_OK != | ||
766 | prepared_statement_run_select (get_dhtkeyuid, 1, rbind, return_ok, NULL, | ||
767 | MYSQL_TYPE_VAR_STRING, &encKey, | ||
768 | max_varchar_len, &k_len, | ||
769 | MYSQL_TYPE_LONGLONG, ¤t_trial, | ||
770 | GNUNET_YES, -1))) | ||
771 | { | ||
772 | return GNUNET_SYSERR; | ||
773 | } | ||
774 | |||
775 | return GNUNET_OK; | ||
776 | } | ||
777 | |||
778 | /** | ||
779 | * Run a prepared statement that does NOT produce results. | ||
780 | * | ||
781 | * @param s handle to the statement we should execute | ||
782 | * @param insert_id NULL or address where to store the row ID of whatever | ||
783 | * was inserted (only for INSERT statements!) | ||
784 | * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective | ||
785 | * values (size + buffer-reference for pointers); terminated | ||
786 | * with "-1" | ||
787 | * | ||
788 | * @return GNUNET_SYSERR on error, otherwise | ||
789 | * the number of successfully affected rows | ||
790 | */ | ||
791 | int | ||
792 | prepared_statement_run (struct StatementHandle *s, | ||
793 | unsigned long long *insert_id, ...) | ||
794 | { | ||
795 | va_list ap; | ||
796 | int affected; | ||
797 | |||
798 | if (GNUNET_OK != prepare_statement (s)) | ||
799 | { | ||
800 | GNUNET_break (0); | ||
801 | return GNUNET_SYSERR; | ||
802 | } | ||
803 | GNUNET_assert (s->valid == GNUNET_YES); | ||
804 | if (s->statement == NULL) | ||
805 | return GNUNET_SYSERR; | ||
806 | |||
807 | va_start (ap, insert_id); | ||
808 | |||
809 | if (GNUNET_OK != init_params (s, ap)) | ||
810 | { | ||
811 | va_end (ap); | ||
812 | return GNUNET_SYSERR; | ||
813 | } | ||
814 | |||
815 | va_end (ap); | ||
816 | affected = mysql_stmt_affected_rows (s->statement); | ||
817 | if (NULL != insert_id) | ||
818 | *insert_id = (unsigned long long) mysql_stmt_insert_id (s->statement); | ||
819 | mysql_stmt_reset (s->statement); | ||
820 | |||
821 | return affected; | ||
822 | } | ||
823 | |||
824 | /* | ||
825 | * Inserts the specified trial into the dhttests.trials table | ||
826 | * | ||
827 | * @param trial_info struct containing the data to insert about this trial | ||
828 | * | ||
829 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
830 | */ | ||
831 | int | ||
832 | add_trial (struct GNUNET_DHTLOG_TrialInfo *trial_info) | ||
833 | { | ||
834 | MYSQL_STMT *stmt; | ||
835 | int ret; | ||
836 | unsigned long long m_len; | ||
837 | |||
838 | m_len = strlen (trial_info->message); | ||
839 | |||
840 | stmt = mysql_stmt_init (conn); | ||
841 | if (GNUNET_OK != | ||
842 | (ret = | ||
843 | prepared_statement_run (insert_trial, ¤t_trial, MYSQL_TYPE_LONG, | ||
844 | &trial_info->other_identifier, GNUNET_YES, | ||
845 | MYSQL_TYPE_LONG, &trial_info->num_nodes, | ||
846 | GNUNET_YES, MYSQL_TYPE_LONG, | ||
847 | &trial_info->topology, GNUNET_YES, | ||
848 | MYSQL_TYPE_FLOAT, | ||
849 | &trial_info->topology_percentage, | ||
850 | MYSQL_TYPE_FLOAT, | ||
851 | &trial_info->topology_probability, | ||
852 | MYSQL_TYPE_LONG, &trial_info->blacklist_topology, | ||
853 | GNUNET_YES, MYSQL_TYPE_LONG, | ||
854 | &trial_info->connect_topology, GNUNET_YES, | ||
855 | MYSQL_TYPE_LONG, | ||
856 | &trial_info->connect_topology_option, GNUNET_YES, | ||
857 | MYSQL_TYPE_FLOAT, | ||
858 | &trial_info->connect_topology_option_modifier, | ||
859 | MYSQL_TYPE_LONG, &trial_info->puts, GNUNET_YES, | ||
860 | MYSQL_TYPE_LONG, &trial_info->gets, GNUNET_YES, | ||
861 | MYSQL_TYPE_LONG, &trial_info->concurrent, | ||
862 | GNUNET_YES, MYSQL_TYPE_LONG, | ||
863 | &trial_info->settle_time, GNUNET_YES, | ||
864 | MYSQL_TYPE_LONG, &trial_info->num_rounds, | ||
865 | GNUNET_YES, MYSQL_TYPE_LONG, | ||
866 | &trial_info->malicious_getters, GNUNET_YES, | ||
867 | MYSQL_TYPE_LONG, &trial_info->malicious_putters, | ||
868 | GNUNET_YES, MYSQL_TYPE_LONG, | ||
869 | &trial_info->malicious_droppers, GNUNET_YES, | ||
870 | MYSQL_TYPE_LONG, | ||
871 | &trial_info->malicious_get_frequency, GNUNET_YES, | ||
872 | MYSQL_TYPE_LONG, | ||
873 | &trial_info->malicious_put_frequency, GNUNET_YES, | ||
874 | MYSQL_TYPE_LONG, &trial_info->stop_closest, | ||
875 | GNUNET_YES, MYSQL_TYPE_LONG, | ||
876 | &trial_info->stop_found, GNUNET_YES, | ||
877 | MYSQL_TYPE_LONG, &trial_info->strict_kademlia, | ||
878 | GNUNET_YES, MYSQL_TYPE_LONG, | ||
879 | &trial_info->gets_succeeded, GNUNET_YES, | ||
880 | MYSQL_TYPE_BLOB, trial_info->message, | ||
881 | max_varchar_len + max_varchar_len, &m_len, -1))) | ||
882 | { | ||
883 | if (ret == GNUNET_SYSERR) | ||
884 | { | ||
885 | mysql_stmt_close (stmt); | ||
886 | return GNUNET_SYSERR; | ||
887 | } | ||
888 | } | ||
889 | |||
890 | get_current_trial (¤t_trial); | ||
891 | |||
892 | mysql_stmt_close (stmt); | ||
893 | return GNUNET_OK; | ||
894 | } | ||
895 | |||
896 | /* | ||
897 | * Inserts the specified round into the dhttests.rounds table | ||
898 | * | ||
899 | * @param round_type the type of round that is being started | ||
900 | * @param round_count counter for the round (if applicable) | ||
901 | * | ||
902 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
903 | */ | ||
904 | int | ||
905 | add_round (unsigned int round_type, unsigned int round_count) | ||
906 | { | ||
907 | |||
908 | MYSQL_STMT *stmt; | ||
909 | int ret; | ||
910 | |||
911 | stmt = mysql_stmt_init (conn); | ||
912 | ret = | ||
913 | prepared_statement_run (insert_round, NULL, MYSQL_TYPE_LONGLONG, | ||
914 | ¤t_trial, GNUNET_YES, MYSQL_TYPE_LONG, | ||
915 | &round_type, GNUNET_YES, MYSQL_TYPE_LONG, | ||
916 | &round_count, GNUNET_YES, -1); | ||
917 | mysql_stmt_close (stmt); | ||
918 | if (ret != GNUNET_OK) | ||
919 | return GNUNET_SYSERR; | ||
920 | return ret; | ||
921 | } | ||
922 | |||
923 | /* | ||
924 | * Inserts the specified round results into the | ||
925 | * dhttests.processed_round_details table | ||
926 | * | ||
927 | * @param round_type the type of round that is being started | ||
928 | * @param round_count counter for the round (if applicable) | ||
929 | * @param num_messages the total number of messages initiated | ||
930 | * @param num_messages_succeeded the number of messages that succeeded | ||
931 | * | ||
932 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
933 | */ | ||
934 | int | ||
935 | add_round_details (unsigned int round_type, unsigned int round_count, | ||
936 | unsigned int num_messages, | ||
937 | unsigned int num_messages_succeeded) | ||
938 | { | ||
939 | MYSQL_STMT *stmt; | ||
940 | int ret; | ||
941 | |||
942 | stmt = mysql_stmt_init (conn); | ||
943 | ret = | ||
944 | prepared_statement_run (insert_round_details, NULL, MYSQL_TYPE_LONGLONG, | ||
945 | ¤t_trial, GNUNET_YES, MYSQL_TYPE_LONG, | ||
946 | &round_type, GNUNET_YES, MYSQL_TYPE_LONG, | ||
947 | &round_count, GNUNET_YES, MYSQL_TYPE_LONG, | ||
948 | &num_messages, GNUNET_YES, MYSQL_TYPE_LONG, | ||
949 | &num_messages_succeeded, GNUNET_YES, -1); | ||
950 | mysql_stmt_close (stmt); | ||
951 | if (ret != GNUNET_OK) | ||
952 | return GNUNET_SYSERR; | ||
953 | return ret; | ||
954 | } | ||
955 | |||
956 | /* | ||
957 | * Inserts the specified stats into the dhttests.node_statistics table | ||
958 | * | ||
959 | * @param peer the peer inserting the statistic | ||
960 | * @param route_requests route requests seen | ||
961 | * @param route_forwards route requests forwarded | ||
962 | * @param result_requests route result requests seen | ||
963 | * @param client_requests client requests initiated | ||
964 | * @param result_forwards route results forwarded | ||
965 | * @param gets get requests handled | ||
966 | * @param puts put requests handle | ||
967 | * @param data_inserts data inserted at this node | ||
968 | * @param find_peer_requests find peer requests seen | ||
969 | * @param find_peers_started find peer requests initiated at this node | ||
970 | * @param gets_started get requests initiated at this node | ||
971 | * @param puts_started put requests initiated at this node | ||
972 | * @param find_peer_responses_received find peer responses received locally | ||
973 | * @param get_responses_received get responses received locally | ||
974 | * @param find_peer_responses_sent find peer responses sent from this node | ||
975 | * @param get_responses_sent get responses sent from this node | ||
976 | * | ||
977 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
978 | */ | ||
979 | int | ||
980 | add_stat (const struct GNUNET_PeerIdentity *peer, unsigned int route_requests, | ||
981 | unsigned int route_forwards, unsigned int result_requests, | ||
982 | unsigned int client_requests, unsigned int result_forwards, | ||
983 | unsigned int gets, unsigned int puts, unsigned int data_inserts, | ||
984 | unsigned int find_peer_requests, unsigned int find_peers_started, | ||
985 | unsigned int gets_started, unsigned int puts_started, | ||
986 | unsigned int find_peer_responses_received, | ||
987 | unsigned int get_responses_received, | ||
988 | unsigned int find_peer_responses_sent, | ||
989 | unsigned int get_responses_sent) | ||
990 | { | ||
991 | MYSQL_STMT *stmt; | ||
992 | int ret; | ||
993 | unsigned long long peer_uid; | ||
994 | unsigned long long return_uid; | ||
995 | |||
996 | if (peer == NULL) | ||
997 | return GNUNET_SYSERR; | ||
998 | |||
999 | if (GNUNET_OK != get_node_uid (&peer_uid, &peer->hashPubKey)) | ||
1000 | { | ||
1001 | return GNUNET_SYSERR; | ||
1002 | } | ||
1003 | |||
1004 | stmt = mysql_stmt_init (conn); | ||
1005 | if (GNUNET_OK != | ||
1006 | (ret = | ||
1007 | prepared_statement_run (insert_stat, &return_uid, MYSQL_TYPE_LONGLONG, | ||
1008 | ¤t_trial, GNUNET_YES, MYSQL_TYPE_LONGLONG, | ||
1009 | &peer_uid, GNUNET_YES, MYSQL_TYPE_LONG, | ||
1010 | &route_requests, GNUNET_YES, MYSQL_TYPE_LONG, | ||
1011 | &route_forwards, GNUNET_YES, MYSQL_TYPE_LONG, | ||
1012 | &result_requests, GNUNET_YES, MYSQL_TYPE_LONG, | ||
1013 | &client_requests, GNUNET_YES, MYSQL_TYPE_LONG, | ||
1014 | &result_forwards, GNUNET_YES, MYSQL_TYPE_LONG, | ||
1015 | &gets, GNUNET_YES, MYSQL_TYPE_LONG, &puts, | ||
1016 | GNUNET_YES, MYSQL_TYPE_LONG, &data_inserts, | ||
1017 | GNUNET_YES, MYSQL_TYPE_LONG, &find_peer_requests, | ||
1018 | GNUNET_YES, MYSQL_TYPE_LONG, &find_peers_started, | ||
1019 | GNUNET_YES, MYSQL_TYPE_LONG, &gets_started, | ||
1020 | GNUNET_YES, MYSQL_TYPE_LONG, &puts_started, | ||
1021 | GNUNET_YES, MYSQL_TYPE_LONG, | ||
1022 | &find_peer_responses_received, GNUNET_YES, | ||
1023 | MYSQL_TYPE_LONG, &get_responses_received, | ||
1024 | GNUNET_YES, MYSQL_TYPE_LONG, | ||
1025 | &find_peer_responses_sent, GNUNET_YES, | ||
1026 | MYSQL_TYPE_LONG, &get_responses_sent, GNUNET_YES, | ||
1027 | -1))) | ||
1028 | { | ||
1029 | if (ret == GNUNET_SYSERR) | ||
1030 | { | ||
1031 | mysql_stmt_close (stmt); | ||
1032 | return GNUNET_SYSERR; | ||
1033 | } | ||
1034 | } | ||
1035 | |||
1036 | mysql_stmt_close (stmt); | ||
1037 | return GNUNET_OK; | ||
1038 | } | ||
1039 | |||
1040 | /* | ||
1041 | * Inserts the specified stats into the dhttests.generic_stats table | ||
1042 | * | ||
1043 | * @param peer the peer inserting the statistic | ||
1044 | * @param name the name of the statistic | ||
1045 | * @param section the section of the statistic | ||
1046 | * @param value the value of the statistic | ||
1047 | * | ||
1048 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
1049 | */ | ||
1050 | int | ||
1051 | add_generic_stat (const struct GNUNET_PeerIdentity *peer, const char *name, | ||
1052 | const char *section, uint64_t value) | ||
1053 | { | ||
1054 | unsigned long long peer_uid; | ||
1055 | unsigned long long section_len; | ||
1056 | unsigned long long name_len; | ||
1057 | int ret; | ||
1058 | |||
1059 | if (peer == NULL) | ||
1060 | return GNUNET_SYSERR; | ||
1061 | |||
1062 | if (GNUNET_OK != get_node_uid (&peer_uid, &peer->hashPubKey)) | ||
1063 | { | ||
1064 | return GNUNET_SYSERR; | ||
1065 | } | ||
1066 | |||
1067 | section_len = strlen (section); | ||
1068 | name_len = strlen (name); | ||
1069 | |||
1070 | if (GNUNET_OK != | ||
1071 | (ret = | ||
1072 | prepared_statement_run (insert_generic_stat, NULL, MYSQL_TYPE_LONGLONG, | ||
1073 | ¤t_trial, GNUNET_YES, MYSQL_TYPE_LONGLONG, | ||
1074 | &peer_uid, GNUNET_YES, MYSQL_TYPE_VAR_STRING, | ||
1075 | §ion, max_varchar_len, §ion_len, | ||
1076 | MYSQL_TYPE_VAR_STRING, &name, max_varchar_len, | ||
1077 | &name_len, MYSQL_TYPE_LONGLONG, &value, | ||
1078 | GNUNET_YES, -1))) | ||
1079 | { | ||
1080 | if (ret == GNUNET_SYSERR) | ||
1081 | { | ||
1082 | return GNUNET_SYSERR; | ||
1083 | } | ||
1084 | } | ||
1085 | return GNUNET_OK; | ||
1086 | } | ||
1087 | |||
1088 | /* | ||
1089 | * Inserts the specified dhtkey into the dhttests.dhtkeys table, | ||
1090 | * stores return value of dhttests.dhtkeys.dhtkeyuid into dhtkeyuid | ||
1091 | * | ||
1092 | * @param dhtkeyuid return value | ||
1093 | * @param dhtkey hashcode of key to insert | ||
1094 | * | ||
1095 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
1096 | */ | ||
1097 | int | ||
1098 | add_dhtkey (unsigned long long *dhtkeyuid, const GNUNET_HashCode * dhtkey) | ||
1099 | { | ||
1100 | |||
1101 | int ret; | ||
1102 | struct GNUNET_CRYPTO_HashAsciiEncoded encKey; | ||
1103 | unsigned long long k_len; | ||
1104 | unsigned long long h_len; | ||
1105 | unsigned long long curr_dhtkeyuid; | ||
1106 | |||
1107 | GNUNET_CRYPTO_hash_to_enc (dhtkey, &encKey); | ||
1108 | k_len = strlen ((char *) &encKey); | ||
1109 | h_len = sizeof (GNUNET_HashCode); | ||
1110 | curr_dhtkeyuid = 0; | ||
1111 | ret = get_dhtkey_uid (&curr_dhtkeyuid, dhtkey); | ||
1112 | if (curr_dhtkeyuid != 0) /* dhtkey already exists */ | ||
1113 | { | ||
1114 | if (dhtkeyuid != NULL) | ||
1115 | *dhtkeyuid = curr_dhtkeyuid; | ||
1116 | return GNUNET_OK; | ||
1117 | } | ||
1118 | else if (ret == GNUNET_SYSERR) | ||
1119 | { | ||
1120 | #if DEBUG_DHTLOG | ||
1121 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to get dhtkeyuid!\n"); | ||
1122 | #endif | ||
1123 | } | ||
1124 | |||
1125 | if (GNUNET_OK != | ||
1126 | (ret = | ||
1127 | prepared_statement_run (insert_dhtkey, dhtkeyuid, MYSQL_TYPE_VAR_STRING, | ||
1128 | &encKey, max_varchar_len, &k_len, | ||
1129 | MYSQL_TYPE_LONG, ¤t_trial, GNUNET_YES, | ||
1130 | MYSQL_TYPE_BLOB, dhtkey, | ||
1131 | sizeof (GNUNET_HashCode), &h_len, -1))) | ||
1132 | { | ||
1133 | if (ret == GNUNET_SYSERR) | ||
1134 | { | ||
1135 | return GNUNET_SYSERR; | ||
1136 | } | ||
1137 | } | ||
1138 | |||
1139 | return GNUNET_OK; | ||
1140 | } | ||
1141 | |||
1142 | |||
1143 | |||
1144 | /* | ||
1145 | * Inserts the specified node into the dhttests.nodes table | ||
1146 | * | ||
1147 | * @param nodeuid the inserted node uid | ||
1148 | * @param node the node to insert | ||
1149 | * | ||
1150 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
1151 | */ | ||
1152 | int | ||
1153 | add_node (unsigned long long *nodeuid, struct GNUNET_PeerIdentity *node) | ||
1154 | { | ||
1155 | struct GNUNET_CRYPTO_HashAsciiEncoded encPeer; | ||
1156 | unsigned long p_len; | ||
1157 | unsigned long h_len; | ||
1158 | int ret; | ||
1159 | |||
1160 | if (node == NULL) | ||
1161 | return GNUNET_SYSERR; | ||
1162 | |||
1163 | GNUNET_CRYPTO_hash_to_enc (&node->hashPubKey, &encPeer); | ||
1164 | p_len = (unsigned long) strlen ((char *) &encPeer); | ||
1165 | h_len = sizeof (GNUNET_HashCode); | ||
1166 | if (GNUNET_OK != | ||
1167 | (ret = | ||
1168 | prepared_statement_run (insert_node, nodeuid, MYSQL_TYPE_LONGLONG, | ||
1169 | ¤t_trial, GNUNET_YES, | ||
1170 | MYSQL_TYPE_VAR_STRING, &encPeer, max_varchar_len, | ||
1171 | &p_len, MYSQL_TYPE_BLOB, &node->hashPubKey, | ||
1172 | sizeof (GNUNET_HashCode), &h_len, -1))) | ||
1173 | { | ||
1174 | if (ret == GNUNET_SYSERR) | ||
1175 | { | ||
1176 | return GNUNET_SYSERR; | ||
1177 | } | ||
1178 | } | ||
1179 | return GNUNET_OK; | ||
1180 | } | ||
1181 | |||
1182 | /* | ||
1183 | * Update dhttests.trials table with current server time as end time | ||
1184 | * | ||
1185 | * @param gets_succeeded how many gets did the testcase report as successful | ||
1186 | * | ||
1187 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure. | ||
1188 | */ | ||
1189 | int | ||
1190 | update_trials (unsigned int gets_succeeded) | ||
1191 | { | ||
1192 | int ret; | ||
1193 | |||
1194 | if (GNUNET_OK != | ||
1195 | (ret = | ||
1196 | prepared_statement_run (update_trial, NULL, MYSQL_TYPE_LONG, | ||
1197 | &gets_succeeded, GNUNET_YES, MYSQL_TYPE_LONGLONG, | ||
1198 | ¤t_trial, 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 | /* | ||
1213 | * Update dhttests.nodes table setting the identified | ||
1214 | * node as a malicious dropper. | ||
1215 | * | ||
1216 | * @param peer the peer that was set to be malicious | ||
1217 | * | ||
1218 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure. | ||
1219 | */ | ||
1220 | int | ||
1221 | set_malicious (struct GNUNET_PeerIdentity *peer) | ||
1222 | { | ||
1223 | unsigned long long p_len; | ||
1224 | int ret; | ||
1225 | char *temp_str; | ||
1226 | |||
1227 | temp_str = GNUNET_strdup (GNUNET_h2s_full (&peer->hashPubKey)); | ||
1228 | p_len = strlen (temp_str); | ||
1229 | |||
1230 | if (GNUNET_OK != | ||
1231 | (ret = | ||
1232 | prepared_statement_run (update_node_malicious, NULL, MYSQL_TYPE_LONGLONG, | ||
1233 | ¤t_trial, GNUNET_YES, | ||
1234 | MYSQL_TYPE_VAR_STRING, temp_str, max_varchar_len, | ||
1235 | &p_len, -1))) | ||
1236 | { | ||
1237 | if (ret == GNUNET_SYSERR) | ||
1238 | { | ||
1239 | return GNUNET_SYSERR; | ||
1240 | } | ||
1241 | } | ||
1242 | return GNUNET_OK; | ||
1243 | } | ||
1244 | |||
1245 | |||
1246 | /* | ||
1247 | * Update dhttests.trials table with total connections information | ||
1248 | * | ||
1249 | * @param totalConnections the number of connections | ||
1250 | * | ||
1251 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure. | ||
1252 | */ | ||
1253 | int | ||
1254 | add_connections (unsigned int totalConnections) | ||
1255 | { | ||
1256 | int ret; | ||
1257 | |||
1258 | if (GNUNET_OK != | ||
1259 | (ret = | ||
1260 | prepared_statement_run (update_connection, NULL, MYSQL_TYPE_LONG, | ||
1261 | &totalConnections, GNUNET_YES, | ||
1262 | MYSQL_TYPE_LONGLONG, ¤t_trial, GNUNET_YES, | ||
1263 | -1))) | ||
1264 | { | ||
1265 | if (ret == GNUNET_SYSERR) | ||
1266 | { | ||
1267 | return GNUNET_SYSERR; | ||
1268 | } | ||
1269 | } | ||
1270 | if (ret > 0) | ||
1271 | return GNUNET_OK; | ||
1272 | else | ||
1273 | return GNUNET_SYSERR; | ||
1274 | } | ||
1275 | |||
1276 | /* | ||
1277 | * Inserts the specified query into the dhttests.queries table | ||
1278 | * | ||
1279 | * @param sqlqueruid inserted query uid | ||
1280 | * @param queryid dht query id | ||
1281 | * @param type type of the query | ||
1282 | * @param hops number of hops query traveled | ||
1283 | * @param succeeded whether or not query was successful | ||
1284 | * @param node the node the query hit | ||
1285 | * @param key the key of the query | ||
1286 | * | ||
1287 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure. | ||
1288 | */ | ||
1289 | int | ||
1290 | add_query (unsigned long long *sqlqueryuid, unsigned long long queryid, | ||
1291 | unsigned int type, unsigned int hops, int succeeded, | ||
1292 | const struct GNUNET_PeerIdentity *node, const GNUNET_HashCode * key) | ||
1293 | { | ||
1294 | int ret; | ||
1295 | unsigned long long peer_uid, key_uid; | ||
1296 | |||
1297 | peer_uid = 0; | ||
1298 | key_uid = 0; | ||
1299 | |||
1300 | if ((node != NULL) && | ||
1301 | (GNUNET_OK == get_node_uid (&peer_uid, &node->hashPubKey))) | ||
1302 | { | ||
1303 | |||
1304 | } | ||
1305 | else | ||
1306 | { | ||
1307 | return GNUNET_SYSERR; | ||
1308 | } | ||
1309 | |||
1310 | if ((key != NULL) && (GNUNET_OK == get_dhtkey_uid (&key_uid, key))) | ||
1311 | { | ||
1312 | |||
1313 | } | ||
1314 | else if ((key != NULL) && (key->bits[(512 / 8 / sizeof (unsigned int)) - 1] == 42)) /* Malicious marker */ | ||
1315 | { | ||
1316 | key_uid = 0; | ||
1317 | } | ||
1318 | else | ||
1319 | { | ||
1320 | return GNUNET_SYSERR; | ||
1321 | } | ||
1322 | |||
1323 | if (GNUNET_OK != | ||
1324 | (ret = | ||
1325 | prepared_statement_run (insert_query, sqlqueryuid, MYSQL_TYPE_LONGLONG, | ||
1326 | ¤t_trial, GNUNET_YES, MYSQL_TYPE_LONG, | ||
1327 | &type, GNUNET_NO, MYSQL_TYPE_LONG, &hops, | ||
1328 | GNUNET_YES, MYSQL_TYPE_LONGLONG, &key_uid, | ||
1329 | GNUNET_YES, MYSQL_TYPE_LONGLONG, &queryid, | ||
1330 | GNUNET_YES, MYSQL_TYPE_LONG, &succeeded, | ||
1331 | GNUNET_NO, MYSQL_TYPE_LONGLONG, &peer_uid, | ||
1332 | GNUNET_YES, -1))) | ||
1333 | { | ||
1334 | if (ret == GNUNET_SYSERR) | ||
1335 | { | ||
1336 | return GNUNET_SYSERR; | ||
1337 | } | ||
1338 | } | ||
1339 | if (ret > 0) | ||
1340 | return GNUNET_OK; | ||
1341 | else | ||
1342 | return GNUNET_SYSERR; | ||
1343 | } | ||
1344 | |||
1345 | /* | ||
1346 | * Inserts the specified route information into the dhttests.routes table | ||
1347 | * | ||
1348 | * @param sqlqueruid inserted query uid | ||
1349 | * @param queryid dht query id | ||
1350 | * @param type type of the query | ||
1351 | * @param hops number of hops query traveled | ||
1352 | * @param succeeded whether or not query was successful | ||
1353 | * @param node the node the query hit | ||
1354 | * @param key the key of the query | ||
1355 | * @param from_node the node that sent the message to node | ||
1356 | * @param to_node next node to forward message to | ||
1357 | * | ||
1358 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure. | ||
1359 | */ | ||
1360 | int | ||
1361 | add_route (unsigned long long *sqlqueryuid, unsigned long long queryid, | ||
1362 | unsigned int type, unsigned int hops, int succeeded, | ||
1363 | const struct GNUNET_PeerIdentity *node, const GNUNET_HashCode * key, | ||
1364 | const struct GNUNET_PeerIdentity *from_node, | ||
1365 | const struct GNUNET_PeerIdentity *to_node) | ||
1366 | { | ||
1367 | unsigned long long peer_uid = 0; | ||
1368 | unsigned long long key_uid = 0; | ||
1369 | unsigned long long from_uid = 0; | ||
1370 | unsigned long long to_uid = 0; | ||
1371 | int ret; | ||
1372 | |||
1373 | if (from_node != NULL) | ||
1374 | get_node_uid (&from_uid, &from_node->hashPubKey); | ||
1375 | |||
1376 | if (to_node != NULL) | ||
1377 | get_node_uid (&to_uid, &to_node->hashPubKey); | ||
1378 | else | ||
1379 | to_uid = 0; | ||
1380 | |||
1381 | if ((node != NULL)) | ||
1382 | { | ||
1383 | if (1 != get_node_uid (&peer_uid, &node->hashPubKey)) | ||
1384 | { | ||
1385 | return GNUNET_SYSERR; | ||
1386 | } | ||
1387 | } | ||
1388 | else | ||
1389 | return GNUNET_SYSERR; | ||
1390 | |||
1391 | if ((key != NULL)) | ||
1392 | { | ||
1393 | if (1 != get_dhtkey_uid (&key_uid, key)) | ||
1394 | { | ||
1395 | return GNUNET_SYSERR; | ||
1396 | } | ||
1397 | } | ||
1398 | else | ||
1399 | return GNUNET_SYSERR; | ||
1400 | |||
1401 | if (GNUNET_OK != | ||
1402 | (ret = | ||
1403 | prepared_statement_run (insert_route, sqlqueryuid, MYSQL_TYPE_LONGLONG, | ||
1404 | ¤t_trial, GNUNET_YES, MYSQL_TYPE_LONG, | ||
1405 | &type, GNUNET_NO, MYSQL_TYPE_LONG, &hops, | ||
1406 | GNUNET_YES, MYSQL_TYPE_LONGLONG, &key_uid, | ||
1407 | GNUNET_YES, MYSQL_TYPE_LONGLONG, &queryid, | ||
1408 | GNUNET_YES, MYSQL_TYPE_LONG, &succeeded, | ||
1409 | GNUNET_NO, MYSQL_TYPE_LONGLONG, &peer_uid, | ||
1410 | GNUNET_YES, MYSQL_TYPE_LONGLONG, &from_uid, | ||
1411 | GNUNET_YES, MYSQL_TYPE_LONGLONG, &to_uid, | ||
1412 | GNUNET_YES, -1))) | ||
1413 | { | ||
1414 | if (ret == GNUNET_SYSERR) | ||
1415 | { | ||
1416 | return GNUNET_SYSERR; | ||
1417 | } | ||
1418 | } | ||
1419 | if (ret > 0) | ||
1420 | return GNUNET_OK; | ||
1421 | else | ||
1422 | return GNUNET_SYSERR; | ||
1423 | } | ||
1424 | |||
1425 | /* | ||
1426 | * Update dhttests.topology table with total connections information | ||
1427 | * | ||
1428 | * @param totalConnections the number of connections | ||
1429 | * | ||
1430 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure. | ||
1431 | */ | ||
1432 | int | ||
1433 | update_current_topology (unsigned int connections) | ||
1434 | { | ||
1435 | int ret; | ||
1436 | unsigned long long topologyuid; | ||
1437 | |||
1438 | get_current_topology (&topologyuid); | ||
1439 | |||
1440 | if (GNUNET_OK != | ||
1441 | (ret = | ||
1442 | prepared_statement_run (update_topology, NULL, MYSQL_TYPE_LONG, | ||
1443 | &connections, GNUNET_YES, MYSQL_TYPE_LONGLONG, | ||
1444 | &topologyuid, GNUNET_YES, -1))) | ||
1445 | { | ||
1446 | if (ret == GNUNET_SYSERR) | ||
1447 | { | ||
1448 | return GNUNET_SYSERR; | ||
1449 | } | ||
1450 | } | ||
1451 | if (ret > 0) | ||
1452 | return GNUNET_OK; | ||
1453 | return GNUNET_SYSERR; | ||
1454 | |||
1455 | } | ||
1456 | |||
1457 | /* | ||
1458 | * Records the current topology (number of connections, time, trial) | ||
1459 | * | ||
1460 | * @param num_connections how many connections are in the topology | ||
1461 | * | ||
1462 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
1463 | */ | ||
1464 | int | ||
1465 | add_topology (int num_connections) | ||
1466 | { | ||
1467 | int ret; | ||
1468 | |||
1469 | if (GNUNET_OK != | ||
1470 | (ret = | ||
1471 | prepared_statement_run (insert_topology, NULL, MYSQL_TYPE_LONGLONG, | ||
1472 | ¤t_trial, GNUNET_YES, MYSQL_TYPE_LONG, | ||
1473 | &num_connections, GNUNET_YES, -1))) | ||
1474 | { | ||
1475 | if (ret == GNUNET_SYSERR) | ||
1476 | { | ||
1477 | return GNUNET_SYSERR; | ||
1478 | } | ||
1479 | } | ||
1480 | if (ret > 0) | ||
1481 | return GNUNET_OK; | ||
1482 | return GNUNET_SYSERR; | ||
1483 | } | ||
1484 | |||
1485 | /* | ||
1486 | * Records a connection between two peers in the current topology | ||
1487 | * | ||
1488 | * @param first one side of the connection | ||
1489 | * @param second other side of the connection | ||
1490 | * | ||
1491 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
1492 | */ | ||
1493 | int | ||
1494 | add_extended_topology (const struct GNUNET_PeerIdentity *first, | ||
1495 | const struct GNUNET_PeerIdentity *second) | ||
1496 | { | ||
1497 | int ret; | ||
1498 | unsigned long long first_uid; | ||
1499 | unsigned long long second_uid; | ||
1500 | unsigned long long topologyuid; | ||
1501 | |||
1502 | if (GNUNET_OK != get_current_topology (&topologyuid)) | ||
1503 | return GNUNET_SYSERR; | ||
1504 | if (GNUNET_OK != get_node_uid (&first_uid, &first->hashPubKey)) | ||
1505 | return GNUNET_SYSERR; | ||
1506 | if (GNUNET_OK != get_node_uid (&second_uid, &second->hashPubKey)) | ||
1507 | return GNUNET_SYSERR; | ||
1508 | |||
1509 | if (GNUNET_OK != | ||
1510 | (ret = | ||
1511 | prepared_statement_run (extend_topology, NULL, MYSQL_TYPE_LONGLONG, | ||
1512 | &topologyuid, GNUNET_YES, MYSQL_TYPE_LONGLONG, | ||
1513 | &first_uid, GNUNET_YES, MYSQL_TYPE_LONGLONG, | ||
1514 | &second_uid, GNUNET_YES, -1))) | ||
1515 | { | ||
1516 | if (ret == GNUNET_SYSERR) | ||
1517 | { | ||
1518 | return GNUNET_SYSERR; | ||
1519 | } | ||
1520 | } | ||
1521 | if (ret > 0) | ||
1522 | return GNUNET_OK; | ||
1523 | return GNUNET_SYSERR; | ||
1524 | } | ||
1525 | |||
1526 | |||
1527 | /* | ||
1528 | * Provides the dhtlog api | ||
1529 | * | ||
1530 | * @param c the configuration to use to connect to a server | ||
1531 | * | ||
1532 | * @return the handle to the server, or NULL on error | ||
1533 | */ | ||
1534 | void * | ||
1535 | libgnunet_plugin_dhtlog_mysql_init (void *cls) | ||
1536 | { | ||
1537 | struct GNUNET_DHTLOG_Plugin *plugin = cls; | ||
1538 | |||
1539 | cfg = plugin->cfg; | ||
1540 | max_varchar_len = 255; | ||
1541 | #if DEBUG_DHTLOG | ||
1542 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1543 | "MySQL DHT Logger: initializing database\n"); | ||
1544 | #endif | ||
1545 | |||
1546 | if (iopen (plugin) != GNUNET_OK) | ||
1547 | { | ||
1548 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1549 | _ | ||
1550 | ("Failed to initialize MySQL database connection for dhtlog.\n")); | ||
1551 | return NULL; | ||
1552 | } | ||
1553 | |||
1554 | GNUNET_assert (plugin->dhtlog_api == NULL); | ||
1555 | plugin->dhtlog_api = GNUNET_malloc (sizeof (struct GNUNET_DHTLOG_Handle)); | ||
1556 | plugin->dhtlog_api->insert_trial = &add_trial; | ||
1557 | plugin->dhtlog_api->insert_stat = &add_stat; | ||
1558 | plugin->dhtlog_api->insert_round = &add_round; | ||
1559 | plugin->dhtlog_api->insert_round_details = &add_round_details; | ||
1560 | plugin->dhtlog_api->add_generic_stat = &add_generic_stat; | ||
1561 | plugin->dhtlog_api->insert_query = &add_query; | ||
1562 | plugin->dhtlog_api->update_trial = &update_trials; | ||
1563 | plugin->dhtlog_api->insert_route = &add_route; | ||
1564 | plugin->dhtlog_api->insert_node = &add_node; | ||
1565 | plugin->dhtlog_api->insert_dhtkey = &add_dhtkey; | ||
1566 | plugin->dhtlog_api->update_connections = &add_connections; | ||
1567 | plugin->dhtlog_api->insert_topology = &add_topology; | ||
1568 | plugin->dhtlog_api->update_topology = &update_current_topology; | ||
1569 | plugin->dhtlog_api->insert_extended_topology = &add_extended_topology; | ||
1570 | plugin->dhtlog_api->set_malicious = &set_malicious; | ||
1571 | get_current_trial (¤t_trial); | ||
1572 | |||
1573 | return plugin; | ||
1574 | } | ||
1575 | |||
1576 | /** | ||
1577 | * Shutdown the plugin. | ||
1578 | */ | ||
1579 | void * | ||
1580 | libgnunet_plugin_dhtlog_mysql_done (void *cls) | ||
1581 | { | ||
1582 | struct GNUNET_DHTLOG_Handle *dhtlog_api = cls; | ||
1583 | |||
1584 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MySQL DHT Logger: database shutdown\n"); | ||
1585 | GNUNET_assert (dhtlog_api != NULL); | ||
1586 | prepared_statement_close (insert_query); | ||
1587 | prepared_statement_close (insert_route); | ||
1588 | prepared_statement_close (insert_trial); | ||
1589 | prepared_statement_close (insert_round); | ||
1590 | prepared_statement_close (insert_round_details); | ||
1591 | prepared_statement_close (insert_node); | ||
1592 | prepared_statement_close (insert_dhtkey); | ||
1593 | prepared_statement_close (update_trial); | ||
1594 | prepared_statement_close (get_dhtkeyuid); | ||
1595 | prepared_statement_close (get_nodeuid); | ||
1596 | prepared_statement_close (update_connection); | ||
1597 | prepared_statement_close (get_trial); | ||
1598 | prepared_statement_close (get_topology); | ||
1599 | prepared_statement_close (insert_topology); | ||
1600 | prepared_statement_close (update_topology); | ||
1601 | prepared_statement_close (extend_topology); | ||
1602 | prepared_statement_close (update_node_malicious); | ||
1603 | |||
1604 | if (conn != NULL) | ||
1605 | mysql_close (conn); | ||
1606 | conn = NULL; | ||
1607 | mysql_library_end (); | ||
1608 | GNUNET_free (dhtlog_api); | ||
1609 | return NULL; | ||
1610 | } | ||
1611 | |||
1612 | /* end of plugin_dhtlog_mysql.c */ | ||
diff --git a/src/dht/plugin_dhtlog_mysql_dump.c b/src/dht/plugin_dhtlog_mysql_dump.c deleted file mode 100644 index bbb1da0c9..000000000 --- a/src/dht/plugin_dhtlog_mysql_dump.c +++ /dev/null | |||
@@ -1,964 +0,0 @@ | |||
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_dump.c | ||
23 | * @brief MySQL logging plugin to record DHT operations to MySQL server, | ||
24 | * but write all queries to file instead of the actual server | ||
25 | * so that they can be imported later. The idea is that connecting | ||
26 | * to the MySQL server X times can be really problematic, but hopefully | ||
27 | * writing to a single file is more reliable. | ||
28 | * @author Nathan Evans | ||
29 | * | ||
30 | * Database: MySQL | ||
31 | */ | ||
32 | |||
33 | #include "platform.h" | ||
34 | #include "gnunet_util_lib.h" | ||
35 | #include "dhtlog.h" | ||
36 | |||
37 | |||
38 | #define DEBUG_DHTLOG GNUNET_YES | ||
39 | |||
40 | /** | ||
41 | * Maximum number of supported parameters for a prepared | ||
42 | * statement. Increase if needed. | ||
43 | */ | ||
44 | #define MAX_PARAM 32 | ||
45 | |||
46 | |||
47 | static unsigned long max_varchar_len; | ||
48 | |||
49 | /** | ||
50 | * The configuration the DHT service is running with | ||
51 | */ | ||
52 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
53 | |||
54 | #define INSERT_QUERIES_STMT "prepare insert_query from 'INSERT INTO queries (trialuid, querytype, hops, dhtkeyuid, dhtqueryid, succeeded, nodeuid, time) "\ | ||
55 | "VALUES (@temp_trial, ?, ?, ?, ?, ?, ?, ?)'" | ||
56 | |||
57 | #define INSERT_ROUTES_STMT "prepare insert_route from 'INSERT INTO routes (trialuid, querytype, hops, dhtkeyuid, dhtqueryid, succeeded, nodeuid, from_node, to_node) "\ | ||
58 | "VALUES (@temp_trial, ?, ?, ?, ?, ?, ?, ?, ?)'" | ||
59 | |||
60 | #define INSERT_NODES_STMT "prepare insert_node from 'INSERT ignore INTO nodes (trialuid, nodeid) "\ | ||
61 | "VALUES (@temp_trial, ?)'" | ||
62 | |||
63 | #define INSERT_TOPOLOGY_STMT "prepare insert_topology from 'INSERT INTO topology (trialuid, date, connections) "\ | ||
64 | "VALUES (@temp_trial, ?, ?)'" | ||
65 | |||
66 | #define INSERT_ROUND_STMT "prepare insert_round from 'INSERT INTO rounds (trialuid, round_type, round_count, starttime) VALUES (@temp_trial, @rtype, @rcount, @curr_time)'" | ||
67 | |||
68 | #define INSERT_ROUND_DETAILS_STMT "prepare insert_round_details from 'INSERT INTO processed_trial_rounds "\ | ||
69 | "(trialuid, round_type, round_count, starttime, endtime, num_messages, num_messages_succeeded)"\ | ||
70 | "VALUES (@temp_trial, @rtype, @rcount, @curr_time, @curr_time, @totalmsgs, @msgssucceeded)'" | ||
71 | |||
72 | #define EXTEND_TOPOLOGY_STMT "prepare extend_topology from 'INSERT INTO extended_topology (topology_uid, uid_first, uid_second) "\ | ||
73 | "VALUES (@temp_topology, ?, ?)'" | ||
74 | |||
75 | #define UPDATE_TOPOLOGY_STMT "prepare update_topology from 'update topology set connections = ? where topology_uid = @temp_topology'" | ||
76 | |||
77 | #define SET_MALICIOUS_STMT "prepare set_malicious from 'update nodes set malicious_dropper = 1 where trialuid = @temp_trial and nodeid = @temp_node'" | ||
78 | |||
79 | #define INSERT_TRIALS_STMT "prepare insert_trial from 'INSERT INTO trials"\ | ||
80 | "(starttime, other_trial_identifier, numnodes, topology,"\ | ||
81 | "topology_percentage, topology_probability,"\ | ||
82 | "blacklist_topology, connect_topology, connect_topology_option,"\ | ||
83 | "connect_topology_option_modifier, puts, gets, "\ | ||
84 | "concurrent, settle_time, num_rounds, malicious_getters,"\ | ||
85 | "malicious_putters, malicious_droppers, malicious_get_frequency,"\ | ||
86 | "malicious_put_frequency, stop_closest, stop_found, strict_kademlia, "\ | ||
87 | "gets_succeeded, message) "\ | ||
88 | "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'" | ||
89 | |||
90 | #define INSERT_GENERIC_STAT_STMT "prepare insert_generic_stat from 'INSERT INTO generic_stats" \ | ||
91 | "(trialuid, nodeuid, section, name, value)"\ | ||
92 | "VALUES (@temp_trial, @temp_node, @temp_section, @temp_stat, @temp_value)'" | ||
93 | |||
94 | #define INSERT_STAT_STMT "prepare insert_stat from 'INSERT INTO node_statistics"\ | ||
95 | "(trialuid, nodeuid, route_requests,"\ | ||
96 | "route_forwards, result_requests,"\ | ||
97 | "client_results, result_forwards, gets,"\ | ||
98 | "puts, data_inserts, find_peer_requests, "\ | ||
99 | "find_peers_started, gets_started, puts_started, find_peer_responses_received,"\ | ||
100 | "get_responses_received, find_peer_responses_sent, get_responses_sent) "\ | ||
101 | "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'" | ||
102 | |||
103 | #define INSERT_DHTKEY_STMT "prepare insert_dhtkey from 'INSERT ignore INTO dhtkeys (dhtkey, trialuid) "\ | ||
104 | "VALUES (?, @temp_trial)'" | ||
105 | |||
106 | #define UPDATE_TRIALS_STMT "prepare update_trial from 'UPDATE trials set endtime= ?, gets_succeeded = ? where trialuid = @temp_trial'" | ||
107 | |||
108 | #define UPDATE_CONNECTIONS_STMT "prepare update_conn from 'UPDATE trials set totalConnections = ? where trialuid = @temp_trial'" | ||
109 | |||
110 | #define GET_TRIAL_STMT "prepare select_trial from 'SELECT MAX( trialuid ) FROM trials into @temp_trial'" | ||
111 | |||
112 | #define GET_TOPOLOGY_STMT "prepare select_topology from 'SELECT MAX( topology_uid ) FROM topology into @temp_topology'" | ||
113 | |||
114 | #define GET_DHTKEYUID_STMT "prepare get_dhtkeyuid from 'SELECT dhtkeyuid FROM dhtkeys where dhtkey = ? and trialuid = @temp_trial'" | ||
115 | |||
116 | #define GET_NODEUID_STMT "prepare get_nodeuid from 'SELECT nodeuid FROM nodes where trialuid = @temp_trial and nodeid = ?'" | ||
117 | |||
118 | #define DATE_STR_SIZE 50 | ||
119 | |||
120 | /** | ||
121 | * File to dump all sql statements to. | ||
122 | */ | ||
123 | FILE *outfile; | ||
124 | |||
125 | |||
126 | static char * | ||
127 | get_sql_time () | ||
128 | { | ||
129 | static char date[DATE_STR_SIZE]; | ||
130 | time_t timetmp; | ||
131 | struct tm *tmptr; | ||
132 | |||
133 | time (&timetmp); | ||
134 | memset (date, 0, DATE_STR_SIZE); | ||
135 | tmptr = localtime (&timetmp); | ||
136 | if (NULL != tmptr) | ||
137 | strftime (date, DATE_STR_SIZE, "%Y-%m-%d %H:%M:%S", tmptr); | ||
138 | else | ||
139 | strcpy (date, ""); | ||
140 | |||
141 | return date; | ||
142 | } | ||
143 | |||
144 | /** | ||
145 | * Create a prepared statement. | ||
146 | * | ||
147 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
148 | */ | ||
149 | static int | ||
150 | prepared_statement_create (const char *statement) | ||
151 | { | ||
152 | if (fprintf (outfile, "%s;\n", statement) > 0) | ||
153 | return GNUNET_OK; | ||
154 | |||
155 | return GNUNET_SYSERR; | ||
156 | } | ||
157 | |||
158 | /* | ||
159 | * Initialize the prepared statements for use with dht test logging | ||
160 | */ | ||
161 | static int | ||
162 | iopen () | ||
163 | { | ||
164 | #define PINIT(a) (GNUNET_OK != (prepared_statement_create(a))) | ||
165 | if (PINIT (INSERT_QUERIES_STMT) || PINIT (INSERT_ROUTES_STMT) || | ||
166 | PINIT (INSERT_ROUND_STMT) || PINIT (INSERT_ROUND_DETAILS_STMT) || | ||
167 | PINIT (INSERT_TRIALS_STMT) || PINIT (SET_MALICIOUS_STMT) || | ||
168 | PINIT (INSERT_GENERIC_STAT_STMT) || PINIT (INSERT_STAT_STMT) || | ||
169 | PINIT (INSERT_NODES_STMT) || PINIT (INSERT_DHTKEY_STMT) || | ||
170 | PINIT (UPDATE_TRIALS_STMT) || PINIT (GET_DHTKEYUID_STMT) || | ||
171 | PINIT (GET_NODEUID_STMT) || PINIT (UPDATE_CONNECTIONS_STMT) || | ||
172 | PINIT (INSERT_TOPOLOGY_STMT) || PINIT (EXTEND_TOPOLOGY_STMT) || | ||
173 | PINIT (UPDATE_TOPOLOGY_STMT) || PINIT (GET_TRIAL_STMT) || | ||
174 | PINIT (GET_TOPOLOGY_STMT)) | ||
175 | { | ||
176 | return GNUNET_SYSERR; | ||
177 | } | ||
178 | #undef PINIT | ||
179 | |||
180 | return GNUNET_OK; | ||
181 | } | ||
182 | |||
183 | /* | ||
184 | * Inserts the specified round into the dhttests.rounds table | ||
185 | * | ||
186 | * @param round_type the type of round that is being started | ||
187 | * @param round_count counter for the round (if applicable) | ||
188 | * | ||
189 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
190 | */ | ||
191 | int | ||
192 | add_round (unsigned int round_type, unsigned int round_count) | ||
193 | { | ||
194 | int ret; | ||
195 | |||
196 | if (outfile == NULL) | ||
197 | return GNUNET_SYSERR; | ||
198 | |||
199 | ret = | ||
200 | fprintf (outfile, | ||
201 | "set @curr_time = \"%s\", @rtype = \"%u\", @rcount = \"%u\";\n", | ||
202 | get_sql_time (), round_type, round_count); | ||
203 | |||
204 | if (ret < 0) | ||
205 | return GNUNET_SYSERR; | ||
206 | ret = fprintf (outfile, "execute insert_round;\n"); | ||
207 | |||
208 | if (ret >= 0) | ||
209 | return GNUNET_OK; | ||
210 | return GNUNET_SYSERR; | ||
211 | } | ||
212 | |||
213 | /* | ||
214 | * Inserts the specified round results into the | ||
215 | * dhttests.processed_round_details table | ||
216 | * | ||
217 | * @param round_type the type of round that is being started | ||
218 | * @param round_count counter for the round (if applicable) | ||
219 | * @param num_messages the total number of messages initiated | ||
220 | * @param num_messages_succeeded the number of messages that succeeded | ||
221 | * | ||
222 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
223 | */ | ||
224 | int | ||
225 | add_round_details (unsigned int round_type, unsigned int round_count, | ||
226 | unsigned int num_messages, | ||
227 | unsigned int num_messages_succeeded) | ||
228 | { | ||
229 | int ret; | ||
230 | |||
231 | if (outfile == NULL) | ||
232 | return GNUNET_SYSERR; | ||
233 | |||
234 | ret = | ||
235 | fprintf (outfile, | ||
236 | "set @curr_time = \"%s\", @rtype = \"%u\", @rcount = \"%u\", @totalmsgs = \"%u\", @msgssucceeded = \"%u\";\n", | ||
237 | get_sql_time (), round_type, round_count, num_messages, | ||
238 | num_messages_succeeded); | ||
239 | |||
240 | if (ret < 0) | ||
241 | return GNUNET_SYSERR; | ||
242 | ret = fprintf (outfile, "execute insert_round_details;\n"); | ||
243 | |||
244 | if (ret >= 0) | ||
245 | return GNUNET_OK; | ||
246 | return GNUNET_SYSERR; | ||
247 | } | ||
248 | |||
249 | /* | ||
250 | * Records the current topology (number of connections, time, trial) | ||
251 | * | ||
252 | * @param num_connections how many connections are in the topology | ||
253 | * | ||
254 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
255 | */ | ||
256 | int | ||
257 | add_topology (int num_connections) | ||
258 | { | ||
259 | int ret; | ||
260 | |||
261 | if (outfile == NULL) | ||
262 | return GNUNET_SYSERR; | ||
263 | |||
264 | ret = | ||
265 | fprintf (outfile, "set @date = \"%s\", @num = %d;\n", get_sql_time (), | ||
266 | num_connections); | ||
267 | |||
268 | if (ret < 0) | ||
269 | return GNUNET_SYSERR; | ||
270 | ret = fprintf (outfile, "execute insert_topology using " "@date, @num;\n"); | ||
271 | if (ret < 0) | ||
272 | return GNUNET_SYSERR; | ||
273 | |||
274 | ret = fprintf (outfile, "execute select_topology;\n"); | ||
275 | |||
276 | if (ret >= 0) | ||
277 | return GNUNET_OK; | ||
278 | return GNUNET_SYSERR; | ||
279 | } | ||
280 | |||
281 | /* | ||
282 | * Records a connection between two peers in the current topology | ||
283 | * | ||
284 | * @param first one side of the connection | ||
285 | * @param second other side of the connection | ||
286 | * | ||
287 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
288 | */ | ||
289 | int | ||
290 | add_extended_topology (const struct GNUNET_PeerIdentity *first, | ||
291 | const struct GNUNET_PeerIdentity *second) | ||
292 | { | ||
293 | int ret; | ||
294 | |||
295 | if (outfile == NULL) | ||
296 | return GNUNET_SYSERR; | ||
297 | |||
298 | if (first != NULL) | ||
299 | ret = | ||
300 | fprintf (outfile, | ||
301 | "select nodeuid from nodes where trialuid = @temp_trial and nodeid = \"%s\" into @temp_first_node;\n", | ||
302 | GNUNET_h2s_full (&first->hashPubKey)); | ||
303 | else | ||
304 | ret = fprintf (outfile, "set @temp_first_node = 0;\n"); | ||
305 | |||
306 | if (ret < 0) | ||
307 | return GNUNET_SYSERR; | ||
308 | |||
309 | if (second != NULL) | ||
310 | ret = | ||
311 | fprintf (outfile, | ||
312 | "select nodeuid from nodes where trialuid = @temp_trial and nodeid = \"%s\" into @temp_second_node;\n", | ||
313 | GNUNET_h2s_full (&second->hashPubKey)); | ||
314 | else | ||
315 | ret = fprintf (outfile, "set @temp_second_node = 0;\n"); | ||
316 | |||
317 | if (ret < 0) | ||
318 | return GNUNET_SYSERR; | ||
319 | |||
320 | ret = | ||
321 | fprintf (outfile, | ||
322 | "execute extend_topology using " | ||
323 | "@temp_first_node, @temp_second_node;\n"); | ||
324 | |||
325 | if (ret >= 0) | ||
326 | return GNUNET_OK; | ||
327 | return GNUNET_SYSERR; | ||
328 | } | ||
329 | |||
330 | |||
331 | /* | ||
332 | * Inserts the specified trial into the dhttests.trials table | ||
333 | * | ||
334 | * @param trial_info struct containing the data to insert about this trial | ||
335 | * | ||
336 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
337 | */ | ||
338 | int | ||
339 | add_trial (struct GNUNET_DHTLOG_TrialInfo *trial_info) | ||
340 | { | ||
341 | int ret; | ||
342 | |||
343 | if (outfile == NULL) | ||
344 | return GNUNET_SYSERR; | ||
345 | |||
346 | ret = | ||
347 | fprintf (outfile, | ||
348 | "set @date = \"%s\", @oid = %u, @num = %u, @topology = %u, @bl = %u, " | ||
349 | "@connect = %u, @c_t_o = %u, @c_t_o_m = %f, @t_p = %f, " | ||
350 | "@t_pr = %f, @puts = %u, @gets = %u, " | ||
351 | "@concurrent = %u, @settle = %u, @rounds = %u, " | ||
352 | "@m_gets = %u, @m_puts = %u, @m_drops = %u, " | ||
353 | "@m_g_f = %u, @m_p_f = %u, @s_c = %u, @s_f = %u," | ||
354 | "@s_k = %u, @g_s = %u, @message = \"%s\";\n", get_sql_time (), | ||
355 | trial_info->other_identifier, trial_info->num_nodes, | ||
356 | trial_info->topology, trial_info->blacklist_topology, | ||
357 | trial_info->connect_topology, | ||
358 | trial_info->connect_topology_option, | ||
359 | trial_info->connect_topology_option_modifier, | ||
360 | trial_info->topology_percentage, | ||
361 | trial_info->topology_probability, trial_info->puts, | ||
362 | trial_info->gets, trial_info->concurrent, | ||
363 | trial_info->settle_time, trial_info->num_rounds, | ||
364 | trial_info->malicious_getters, trial_info->malicious_putters, | ||
365 | trial_info->malicious_droppers, | ||
366 | trial_info->malicious_get_frequency, | ||
367 | trial_info->malicious_put_frequency, trial_info->stop_closest, | ||
368 | trial_info->stop_found, trial_info->strict_kademlia, | ||
369 | trial_info->gets_succeeded, trial_info->message); | ||
370 | |||
371 | if (ret < 0) | ||
372 | return GNUNET_SYSERR; | ||
373 | ret = | ||
374 | fprintf (outfile, | ||
375 | "execute insert_trial using " | ||
376 | "@date, @oid, @num, @topology, @t_p, @t_pr," | ||
377 | " @bl, @connect, @c_t_o," "@c_t_o_m, @puts, @gets," | ||
378 | "@concurrent, @settle, @rounds," "@m_gets, @m_puts, @m_drops," | ||
379 | "@m_g_f, @m_p_f, @s_c, @s_f," "@s_k, @g_s, @message;\n"); | ||
380 | if (ret < 0) | ||
381 | return GNUNET_SYSERR; | ||
382 | ret = fprintf (outfile, "execute select_trial;\n"); | ||
383 | |||
384 | if (ret >= 0) | ||
385 | return GNUNET_OK; | ||
386 | return GNUNET_SYSERR; | ||
387 | } | ||
388 | |||
389 | |||
390 | /* | ||
391 | * Inserts the specified stats into the dhttests.generic_stats table | ||
392 | * | ||
393 | * @param peer the peer inserting the statistic | ||
394 | * @param name the name of the statistic | ||
395 | * @param section the section of the statistic | ||
396 | * @param value the value of the statistic | ||
397 | * | ||
398 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
399 | */ | ||
400 | int | ||
401 | add_generic_stat (const struct GNUNET_PeerIdentity *peer, const char *name, | ||
402 | const char *section, uint64_t value) | ||
403 | { | ||
404 | int ret; | ||
405 | |||
406 | if (outfile == NULL) | ||
407 | return GNUNET_SYSERR; | ||
408 | |||
409 | if (peer != NULL) | ||
410 | ret = | ||
411 | fprintf (outfile, | ||
412 | "select nodeuid from nodes where trialuid = @temp_trial and nodeid = \"%s\" into @temp_node;\n", | ||
413 | GNUNET_h2s_full (&peer->hashPubKey)); | ||
414 | else | ||
415 | ret = fprintf (outfile, "set @temp_node = 0;\n"); | ||
416 | |||
417 | if (ret < 0) | ||
418 | return GNUNET_SYSERR; | ||
419 | |||
420 | ret = | ||
421 | fprintf (outfile, | ||
422 | "set @temp_section = \"%s\", @temp_stat = \"%s\", @temp_value = %llu;\n", | ||
423 | section, name, (unsigned long long) value); | ||
424 | |||
425 | if (ret < 0) | ||
426 | return GNUNET_SYSERR; | ||
427 | |||
428 | ret = fprintf (outfile, "execute insert_generic_stat;\n"); | ||
429 | |||
430 | if (ret < 0) | ||
431 | return GNUNET_SYSERR; | ||
432 | return GNUNET_OK; | ||
433 | } | ||
434 | |||
435 | |||
436 | /* | ||
437 | * Inserts the specified stats into the dhttests.node_statistics table | ||
438 | * | ||
439 | * @param peer the peer inserting the statistic | ||
440 | * @param route_requests route requests seen | ||
441 | * @param route_forwards route requests forwarded | ||
442 | * @param result_requests route result requests seen | ||
443 | * @param client_requests client requests initiated | ||
444 | * @param result_forwards route results forwarded | ||
445 | * @param gets get requests handled | ||
446 | * @param puts put requests handle | ||
447 | * @param data_inserts data inserted at this node | ||
448 | * @param find_peer_requests find peer requests seen | ||
449 | * @param find_peers_started find peer requests initiated at this node | ||
450 | * @param gets_started get requests initiated at this node | ||
451 | * @param puts_started put requests initiated at this node | ||
452 | * @param find_peer_responses_received find peer responses received locally | ||
453 | * @param get_responses_received get responses received locally | ||
454 | * @param find_peer_responses_sent find peer responses sent from this node | ||
455 | * @param get_responses_sent get responses sent from this node | ||
456 | * | ||
457 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
458 | */ | ||
459 | int | ||
460 | add_stat (const struct GNUNET_PeerIdentity *peer, unsigned int route_requests, | ||
461 | unsigned int route_forwards, unsigned int result_requests, | ||
462 | unsigned int client_requests, unsigned int result_forwards, | ||
463 | unsigned int gets, unsigned int puts, unsigned int data_inserts, | ||
464 | unsigned int find_peer_requests, unsigned int find_peers_started, | ||
465 | unsigned int gets_started, unsigned int puts_started, | ||
466 | unsigned int find_peer_responses_received, | ||
467 | unsigned int get_responses_received, | ||
468 | unsigned int find_peer_responses_sent, | ||
469 | unsigned int get_responses_sent) | ||
470 | { | ||
471 | int ret; | ||
472 | |||
473 | if (outfile == NULL) | ||
474 | return GNUNET_SYSERR; | ||
475 | |||
476 | if (peer != NULL) | ||
477 | ret = | ||
478 | fprintf (outfile, | ||
479 | "select nodeuid from nodes where trialuid = @temp_trial and nodeid = \"%s\" into @temp_node;\n", | ||
480 | GNUNET_h2s_full (&peer->hashPubKey)); | ||
481 | else | ||
482 | ret = fprintf (outfile, "set @temp_node = 0;\n"); | ||
483 | if (ret < 0) | ||
484 | return GNUNET_SYSERR; | ||
485 | |||
486 | ret = | ||
487 | fprintf (outfile, | ||
488 | "set @r_r = %u, @r_f = %u, @res_r = %u, @c_r = %u, " | ||
489 | "@res_f = %u, @gets = %u, @puts = %u, @d_i = %u, " | ||
490 | "@f_p_r = %u, @f_p_s = %u, @g_s = %u, @p_s = %u, " | ||
491 | "@f_p_r_r = %u, @g_r_r = %u, @f_p_r_s = %u, @g_r_s = %u;\n", | ||
492 | route_requests, route_forwards, result_requests, client_requests, | ||
493 | result_forwards, gets, puts, data_inserts, find_peer_requests, | ||
494 | find_peers_started, gets_started, puts_started, | ||
495 | find_peer_responses_received, get_responses_received, | ||
496 | find_peer_responses_sent, get_responses_sent); | ||
497 | |||
498 | if (ret < 0) | ||
499 | return GNUNET_SYSERR; | ||
500 | |||
501 | ret = | ||
502 | fprintf (outfile, | ||
503 | "execute insert_stat using " | ||
504 | "@temp_trial, @temp_node, @r_r, @r_f, @res_r, @c_r, " | ||
505 | "@res_f, @gets, @puts, @d_i, " "@f_p_r, @f_p_s, @g_s, @p_s, " | ||
506 | "@f_p_r_r, @g_r_r, @f_p_r_s, @g_r_s;\n"); | ||
507 | if (ret < 0) | ||
508 | return GNUNET_SYSERR; | ||
509 | return GNUNET_OK; | ||
510 | } | ||
511 | |||
512 | /* | ||
513 | * Inserts the specified dhtkey into the dhttests.dhtkeys table, | ||
514 | * stores return value of dhttests.dhtkeys.dhtkeyuid into dhtkeyuid | ||
515 | * | ||
516 | * @param dhtkeyuid return value | ||
517 | * @param dhtkey hashcode of key to insert | ||
518 | * | ||
519 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
520 | */ | ||
521 | int | ||
522 | add_dhtkey (unsigned long long *dhtkeyuid, const GNUNET_HashCode * dhtkey) | ||
523 | { | ||
524 | int ret; | ||
525 | |||
526 | if (dhtkeyuid != NULL) | ||
527 | *dhtkeyuid = 0; | ||
528 | |||
529 | if (outfile == NULL) | ||
530 | return GNUNET_SYSERR; | ||
531 | |||
532 | if (dhtkey != NULL) | ||
533 | ret = | ||
534 | fprintf (outfile, "set @dhtkey = \"%s\";\n", GNUNET_h2s_full (dhtkey)); | ||
535 | else | ||
536 | ret = fprintf (outfile, "set @dhtkey = XXXXX;\n"); | ||
537 | |||
538 | if (ret < 0) | ||
539 | return GNUNET_SYSERR; | ||
540 | ret = fprintf (outfile, "execute insert_dhtkey using @dhtkey;\n"); | ||
541 | |||
542 | if (ret >= 0) | ||
543 | return GNUNET_OK; | ||
544 | return GNUNET_SYSERR; | ||
545 | } | ||
546 | |||
547 | /* | ||
548 | * Inserts the specified node into the dhttests.nodes table | ||
549 | * | ||
550 | * @param nodeuid the inserted node uid | ||
551 | * @param node the node to insert | ||
552 | * | ||
553 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
554 | */ | ||
555 | int | ||
556 | add_node (unsigned long long *nodeuid, struct GNUNET_PeerIdentity *node) | ||
557 | { | ||
558 | int ret; | ||
559 | |||
560 | if (node == NULL) | ||
561 | return GNUNET_SYSERR; | ||
562 | |||
563 | if (outfile == NULL) | ||
564 | return GNUNET_SYSERR; | ||
565 | |||
566 | ret = | ||
567 | fprintf (outfile, "set @node = \"%s\";\n", | ||
568 | GNUNET_h2s_full (&node->hashPubKey)); | ||
569 | |||
570 | if (ret < 0) | ||
571 | return GNUNET_SYSERR; | ||
572 | |||
573 | ret = fprintf (outfile, "execute insert_node using @node;\n"); | ||
574 | |||
575 | if (ret >= 0) | ||
576 | return GNUNET_OK; | ||
577 | return GNUNET_SYSERR; | ||
578 | } | ||
579 | |||
580 | /* | ||
581 | * Update dhttests.trials table with current server time as end time | ||
582 | * | ||
583 | * @param gets_succeeded how many gets did the testcase report as successful | ||
584 | * | ||
585 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure. | ||
586 | */ | ||
587 | int | ||
588 | update_trials (unsigned int gets_succeeded) | ||
589 | { | ||
590 | int ret; | ||
591 | |||
592 | if (outfile == NULL) | ||
593 | return GNUNET_SYSERR; | ||
594 | |||
595 | ret = | ||
596 | fprintf (outfile, "set @date = \"%s\", @g_s = %u;\n", get_sql_time (), | ||
597 | gets_succeeded); | ||
598 | |||
599 | if (ret < 0) | ||
600 | return GNUNET_SYSERR; | ||
601 | |||
602 | ret = fprintf (outfile, "execute update_trial using @date, @g_s;\n"); | ||
603 | |||
604 | if (ret >= 0) | ||
605 | return GNUNET_OK; | ||
606 | else | ||
607 | return GNUNET_SYSERR; | ||
608 | } | ||
609 | |||
610 | |||
611 | /* | ||
612 | * Update dhttests.nodes table setting the identified | ||
613 | * node as a malicious dropper. | ||
614 | * | ||
615 | * @param peer the peer that was set to be malicious | ||
616 | * | ||
617 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure. | ||
618 | */ | ||
619 | int | ||
620 | set_malicious (struct GNUNET_PeerIdentity *peer) | ||
621 | { | ||
622 | int ret; | ||
623 | |||
624 | if (outfile == NULL) | ||
625 | return GNUNET_SYSERR; | ||
626 | |||
627 | ret = | ||
628 | fprintf (outfile, "set @temp_node = \"%s\";\n", | ||
629 | GNUNET_h2s_full (&peer->hashPubKey)); | ||
630 | |||
631 | if (ret < 0) | ||
632 | return GNUNET_SYSERR; | ||
633 | |||
634 | ret = fprintf (outfile, "execute set_malicious;\n"); | ||
635 | |||
636 | if (ret >= 0) | ||
637 | return GNUNET_OK; | ||
638 | else | ||
639 | return GNUNET_SYSERR; | ||
640 | } | ||
641 | |||
642 | |||
643 | /* | ||
644 | * Update dhttests.trials table with total connections information | ||
645 | * | ||
646 | * @param totalConnections the number of connections | ||
647 | * | ||
648 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure. | ||
649 | */ | ||
650 | int | ||
651 | add_connections (unsigned int totalConnections) | ||
652 | { | ||
653 | int ret; | ||
654 | |||
655 | if (outfile == NULL) | ||
656 | return GNUNET_SYSERR; | ||
657 | |||
658 | ret = fprintf (outfile, "set @conns = %u;\n", totalConnections); | ||
659 | |||
660 | if (ret < 0) | ||
661 | return GNUNET_SYSERR; | ||
662 | |||
663 | ret = fprintf (outfile, "execute update_conn using @conns;\n"); | ||
664 | |||
665 | if (ret >= 0) | ||
666 | return GNUNET_OK; | ||
667 | else | ||
668 | return GNUNET_SYSERR; | ||
669 | } | ||
670 | |||
671 | |||
672 | /* | ||
673 | * Update dhttests.topology table with total connections information | ||
674 | * | ||
675 | * @param totalConnections the number of connections | ||
676 | * | ||
677 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure. | ||
678 | */ | ||
679 | int | ||
680 | update_topology (unsigned int connections) | ||
681 | { | ||
682 | int ret; | ||
683 | |||
684 | if (outfile == NULL) | ||
685 | return GNUNET_SYSERR; | ||
686 | |||
687 | ret = fprintf (outfile, "set @temp_conns = %u;\n", connections); | ||
688 | |||
689 | if (ret < 0) | ||
690 | return GNUNET_SYSERR; | ||
691 | |||
692 | ret = fprintf (outfile, "execute update_topology using @temp_conns;\n"); | ||
693 | |||
694 | if (ret >= 0) | ||
695 | return GNUNET_OK; | ||
696 | else | ||
697 | return GNUNET_SYSERR; | ||
698 | } | ||
699 | |||
700 | /* | ||
701 | * Inserts the specified query into the dhttests.queries table | ||
702 | * | ||
703 | * @param sqlqueruid inserted query uid | ||
704 | * @param queryid dht query id | ||
705 | * @param type type of the query | ||
706 | * @param hops number of hops query traveled | ||
707 | * @param succeeded whether or not query was successful | ||
708 | * @param node the node the query hit | ||
709 | * @param key the key of the query | ||
710 | * | ||
711 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure. | ||
712 | */ | ||
713 | int | ||
714 | add_query (unsigned long long *sqlqueryuid, unsigned long long queryid, | ||
715 | unsigned int type, unsigned int hops, int succeeded, | ||
716 | const struct GNUNET_PeerIdentity *node, const GNUNET_HashCode * key) | ||
717 | { | ||
718 | int ret; | ||
719 | |||
720 | if (outfile == NULL) | ||
721 | return GNUNET_SYSERR; | ||
722 | |||
723 | if (sqlqueryuid != NULL) | ||
724 | *sqlqueryuid = 0; | ||
725 | |||
726 | if (key != NULL) | ||
727 | ret = | ||
728 | fprintf (outfile, | ||
729 | "select dhtkeyuid from dhtkeys where trialuid = @temp_trial and dhtkey = \"%s\" into @temp_dhtkey;\n", | ||
730 | GNUNET_h2s_full (key)); | ||
731 | else | ||
732 | ret = fprintf (outfile, "set @temp_dhtkey = 0;\n"); | ||
733 | |||
734 | if (ret < 0) | ||
735 | return GNUNET_SYSERR; | ||
736 | |||
737 | if (node != NULL) | ||
738 | ret = | ||
739 | fprintf (outfile, | ||
740 | "select nodeuid from nodes where trialuid = @temp_trial and nodeid = \"%s\" into @temp_node;\n", | ||
741 | GNUNET_h2s_full (&node->hashPubKey)); | ||
742 | else | ||
743 | ret = fprintf (outfile, "set @temp_node = 0;\n"); | ||
744 | |||
745 | if (ret < 0) | ||
746 | return GNUNET_SYSERR; | ||
747 | |||
748 | ret = | ||
749 | fprintf (outfile, | ||
750 | "set @qid = %llu, @type = %u, @hops = %u, @succ = %d, @time = \"%s\";\n", | ||
751 | queryid, type, hops, succeeded, get_sql_time ()); | ||
752 | |||
753 | if (ret < 0) | ||
754 | return GNUNET_SYSERR; | ||
755 | |||
756 | ret = | ||
757 | fprintf (outfile, | ||
758 | "execute insert_query using @type, @hops, @temp_dhtkey, @qid, @succ, @temp_node, @time;\n"); | ||
759 | |||
760 | if (ret >= 0) | ||
761 | return GNUNET_OK; | ||
762 | else | ||
763 | return GNUNET_SYSERR; | ||
764 | } | ||
765 | |||
766 | /* | ||
767 | * Inserts the specified route information into the dhttests.routes table | ||
768 | * | ||
769 | * @param sqlqueruid inserted query uid | ||
770 | * @param queryid dht query id | ||
771 | * @param type type of the query | ||
772 | * @param hops number of hops query traveled | ||
773 | * @param succeeded whether or not query was successful | ||
774 | * @param node the node the query hit | ||
775 | * @param key the key of the query | ||
776 | * @param from_node the node that sent the message to node | ||
777 | * @param to_node next node to forward message to | ||
778 | * | ||
779 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure. | ||
780 | */ | ||
781 | int | ||
782 | add_route (unsigned long long *sqlqueryuid, unsigned long long queryid, | ||
783 | unsigned int type, unsigned int hops, int succeeded, | ||
784 | const struct GNUNET_PeerIdentity *node, const GNUNET_HashCode * key, | ||
785 | const struct GNUNET_PeerIdentity *from_node, | ||
786 | const struct GNUNET_PeerIdentity *to_node) | ||
787 | { | ||
788 | int ret; | ||
789 | |||
790 | if (outfile == NULL) | ||
791 | return GNUNET_SYSERR; | ||
792 | |||
793 | if (sqlqueryuid != NULL) | ||
794 | *sqlqueryuid = 0; | ||
795 | |||
796 | if (key != NULL) | ||
797 | ret = | ||
798 | fprintf (outfile, | ||
799 | "select dhtkeyuid from dhtkeys where trialuid = @temp_trial and dhtkey = \"%s\" into @temp_dhtkey;\n", | ||
800 | GNUNET_h2s_full (key)); | ||
801 | else | ||
802 | ret = fprintf (outfile, "set @temp_dhtkey = 0;\n"); | ||
803 | |||
804 | if (ret < 0) | ||
805 | return GNUNET_SYSERR; | ||
806 | |||
807 | if (node != NULL) | ||
808 | ret = | ||
809 | fprintf (outfile, | ||
810 | "select nodeuid from nodes where trialuid = @temp_trial and nodeid = \"%s\" into @temp_node;\n", | ||
811 | GNUNET_h2s_full (&node->hashPubKey)); | ||
812 | else | ||
813 | ret = fprintf (outfile, "set @temp_node = 0;\n"); | ||
814 | |||
815 | if (ret < 0) | ||
816 | return GNUNET_SYSERR; | ||
817 | |||
818 | if (from_node != NULL) | ||
819 | ret = | ||
820 | fprintf (outfile, | ||
821 | "select nodeuid from nodes where trialuid = @temp_trial and nodeid = \"%s\" into @temp_from_node;\n", | ||
822 | GNUNET_h2s_full (&from_node->hashPubKey)); | ||
823 | else | ||
824 | ret = fprintf (outfile, "set @temp_from_node = 0;\n"); | ||
825 | |||
826 | if (ret < 0) | ||
827 | return GNUNET_SYSERR; | ||
828 | |||
829 | if (to_node != NULL) | ||
830 | ret = | ||
831 | fprintf (outfile, | ||
832 | "select nodeuid from nodes where trialuid = @temp_trial and nodeid = \"%s\" into @temp_to_node;\n", | ||
833 | GNUNET_h2s_full (&to_node->hashPubKey)); | ||
834 | else | ||
835 | ret = fprintf (outfile, "set @temp_to_node = 0;\n"); | ||
836 | |||
837 | if (ret < 0) | ||
838 | return GNUNET_SYSERR; | ||
839 | |||
840 | ret = | ||
841 | fprintf (outfile, | ||
842 | "set @qid = %llu, @type = %u, @hops = %u, @succ = %d;\n", | ||
843 | queryid, type, hops, succeeded); | ||
844 | |||
845 | if (ret < 0) | ||
846 | return GNUNET_SYSERR; | ||
847 | |||
848 | ret = | ||
849 | fprintf (outfile, | ||
850 | "execute insert_route using @type, @hops, @temp_dhtkey, @qid, @succ, @temp_node, @temp_from_node, @temp_to_node;\n"); | ||
851 | |||
852 | if (ret >= 0) | ||
853 | return GNUNET_OK; | ||
854 | else | ||
855 | return GNUNET_SYSERR; | ||
856 | } | ||
857 | |||
858 | /* | ||
859 | * Provides the dhtlog api | ||
860 | * | ||
861 | * @param c the configuration to use to connect to a server | ||
862 | * | ||
863 | * @return the handle to the server, or NULL on error | ||
864 | */ | ||
865 | void * | ||
866 | libgnunet_plugin_dhtlog_mysql_dump_init (void *cls) | ||
867 | { | ||
868 | struct GNUNET_DHTLOG_Plugin *plugin = cls; | ||
869 | char *outfile_name; | ||
870 | char *outfile_path; | ||
871 | char *fn; | ||
872 | int dirwarn; | ||
873 | |||
874 | cfg = plugin->cfg; | ||
875 | max_varchar_len = 255; | ||
876 | |||
877 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
878 | "MySQL (DUMP) DHT Logger: initializing\n"); | ||
879 | |||
880 | if (GNUNET_OK != | ||
881 | GNUNET_CONFIGURATION_get_value_string (plugin->cfg, "MYSQLDUMP", "PATH", | ||
882 | &outfile_path)) | ||
883 | { | ||
884 | outfile_path = GNUNET_strdup (""); | ||
885 | } | ||
886 | |||
887 | GNUNET_asprintf (&outfile_name, "%s%s-%d", outfile_path, "mysqldump", | ||
888 | getpid ()); | ||
889 | |||
890 | fn = GNUNET_STRINGS_filename_expand (outfile_name); | ||
891 | |||
892 | if (fn == NULL) | ||
893 | { | ||
894 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
895 | _("Failed to get full path for `%s'\n"), outfile_name); | ||
896 | GNUNET_free (outfile_path); | ||
897 | GNUNET_free (outfile_name); | ||
898 | return NULL; | ||
899 | } | ||
900 | |||
901 | dirwarn = (GNUNET_OK != GNUNET_DISK_directory_create_for_file (fn)); | ||
902 | outfile = FOPEN (fn, "w"); | ||
903 | |||
904 | if (outfile == NULL) | ||
905 | { | ||
906 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "fopen", fn); | ||
907 | if (dirwarn) | ||
908 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
909 | _("Failed to create or access directory for log file `%s'\n"), | ||
910 | fn); | ||
911 | GNUNET_free (outfile_path); | ||
912 | GNUNET_free (outfile_name); | ||
913 | GNUNET_free (fn); | ||
914 | return NULL; | ||
915 | } | ||
916 | |||
917 | GNUNET_free (outfile_path); | ||
918 | GNUNET_free (outfile_name); | ||
919 | GNUNET_free (fn); | ||
920 | |||
921 | if (iopen () != GNUNET_OK) | ||
922 | { | ||
923 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
924 | _("Failed to create file for dhtlog.\n")); | ||
925 | fclose (outfile); | ||
926 | return NULL; | ||
927 | } | ||
928 | GNUNET_assert (plugin->dhtlog_api == NULL); | ||
929 | plugin->dhtlog_api = GNUNET_malloc (sizeof (struct GNUNET_DHTLOG_Handle)); | ||
930 | plugin->dhtlog_api->insert_trial = &add_trial; | ||
931 | plugin->dhtlog_api->insert_round = &add_round; | ||
932 | plugin->dhtlog_api->insert_round_details = &add_round_details; | ||
933 | plugin->dhtlog_api->insert_stat = &add_stat; | ||
934 | plugin->dhtlog_api->insert_query = &add_query; | ||
935 | plugin->dhtlog_api->update_trial = &update_trials; | ||
936 | plugin->dhtlog_api->insert_route = &add_route; | ||
937 | plugin->dhtlog_api->insert_node = &add_node; | ||
938 | plugin->dhtlog_api->insert_dhtkey = &add_dhtkey; | ||
939 | plugin->dhtlog_api->update_connections = &add_connections; | ||
940 | plugin->dhtlog_api->insert_topology = &add_topology; | ||
941 | plugin->dhtlog_api->insert_extended_topology = &add_extended_topology; | ||
942 | plugin->dhtlog_api->update_topology = &update_topology; | ||
943 | plugin->dhtlog_api->set_malicious = &set_malicious; | ||
944 | plugin->dhtlog_api->add_generic_stat = &add_generic_stat; | ||
945 | |||
946 | return plugin; | ||
947 | } | ||
948 | |||
949 | /** | ||
950 | * Shutdown the plugin. | ||
951 | */ | ||
952 | void * | ||
953 | libgnunet_plugin_dhtlog_mysql_dump_done (void *cls) | ||
954 | { | ||
955 | struct GNUNET_DHTLOG_Handle *dhtlog_api = cls; | ||
956 | |||
957 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MySQL DHT Logger: database shutdown\n"); | ||
958 | GNUNET_assert (dhtlog_api != NULL); | ||
959 | |||
960 | GNUNET_free (dhtlog_api); | ||
961 | return NULL; | ||
962 | } | ||
963 | |||
964 | /* end of plugin_dhtlog_mysql.c */ | ||