aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dht/Makefile.am34
-rw-r--r--src/dht/dht.h70
-rw-r--r--src/dht/dht_api.c153
-rw-r--r--src/dht/dht_api_find_peer.c10
-rw-r--r--src/dht/dht_api_get_put.c38
-rw-r--r--src/dht/gnunet-service-dht.c173
-rw-r--r--src/dht/test_dht_api_data.conf3
-rw-r--r--src/dht/test_dht_api_peer1.conf3
-rw-r--r--src/dht/test_dht_multipeer.c34
-rw-r--r--src/dht/test_dht_multipeer_data.conf21
-rw-r--r--src/dht/test_dht_twopeer.c4
-rw-r--r--src/dht/test_dht_twopeer_data.conf3
-rw-r--r--src/dht/test_dht_twopeer_path_tracking.c513
-rw-r--r--src/dht/test_dhtlog.c2
-rw-r--r--src/dht/test_dhtlog_data.conf2
15 files changed, 900 insertions, 163 deletions
diff --git a/src/dht/Makefile.am b/src/dht/Makefile.am
index d361f536a..ddcfccd46 100644
--- a/src/dht/Makefile.am
+++ b/src/dht/Makefile.am
@@ -52,7 +52,7 @@ libgnunet_plugin_dhtlog_mysql_dump_la_LIBADD = \
52 $(XLIB) 52 $(XLIB)
53libgnunet_plugin_dhtlog_mysql_dump_la_LDFLAGS = \ 53libgnunet_plugin_dhtlog_mysql_dump_la_LDFLAGS = \
54 $(GN_PLUGIN_LDFLAGS) 54 $(GN_PLUGIN_LDFLAGS)
55 55
56libgnunet_plugin_dhtlog_mysql_dump_load_la_SOURCES = \ 56libgnunet_plugin_dhtlog_mysql_dump_load_la_SOURCES = \
57 plugin_dhtlog_mysql_dump_load.c 57 plugin_dhtlog_mysql_dump_load.c
58libgnunet_plugin_dhtlog_mysql_dump_load_la_LIBADD = \ 58libgnunet_plugin_dhtlog_mysql_dump_load_la_LIBADD = \
@@ -70,6 +70,7 @@ libgnunetdhtlog_la_LDFLAGS = \
70 -version-info 0:0:0 70 -version-info 0:0:0
71 71
72libgnunetdht_la_SOURCES = \ 72libgnunetdht_la_SOURCES = \
73libgnunetdht_la_SOURCES = \
73 dht_api.c dht.h \ 74 dht_api.c dht.h \
74 dht_api_get_put.c \ 75 dht_api_get_put.c \
75 dht_api_find_peer.c 76 dht_api_find_peer.c
@@ -84,12 +85,10 @@ bin_PROGRAMS = $(STUD_PROGS) \
84 gnunet-service-dht \ 85 gnunet-service-dht \
85 gnunet-dht-get \ 86 gnunet-dht-get \
86 gnunet-dht-get-peer \ 87 gnunet-dht-get-peer \
87 gnunet-dht-put 88 gnunet-dht-put \
89 gnunet-dht-driver
88 90
89if HAVE_MALICIOUS 91noinst_PROGRAMS = $(check_PROGRAMS)
90noinst_PROGRAMS = \
91 gnunet-dht-driver
92endif
93 92
94gnunet_service_dht_SOURCES = \ 93gnunet_service_dht_SOURCES = \
95 gnunet-service-dht.c 94 gnunet-service-dht.c
@@ -151,14 +150,17 @@ check_PROGRAMS = $(STUD_TESTS) \
151 test_dht_api \ 150 test_dht_api \
152 test_dht_twopeer \ 151 test_dht_twopeer \
153 test_dht_twopeer_put_get \ 152 test_dht_twopeer_put_get \
153 test_dht_twopeer_path_tracking \
154 test_dht_multipeer \ 154 test_dht_multipeer \
155 test_dhtlog 155 test_dhtlog
156# test_hash_operations
157 156
158if !DISABLE_TEST_RUN 157if !DISABLE_TEST_RUN
159TESTS = test_dht_api $(check_SCRIPTS) \ 158TESTS = test_dht_api $(check_SCRIPTS) \
160 test_dht_twopeer \ 159 test_dht_twopeer \
161 test_dht_twopeer_put_get 160 test_dht_twopeer_put_get \
161 test_dht_twopeer_path_tracking \
162 test_dht_multipeer \
163 test_dhtlog
162endif 164endif
163 165
164test_dht_api_SOURCES = \ 166test_dht_api_SOURCES = \
@@ -179,13 +181,6 @@ test_dht_multipeer_LDADD = \
179test_dht_multipeer_DEPENDENCIES = \ 181test_dht_multipeer_DEPENDENCIES = \
180 libgnunetdht.la 182 libgnunetdht.la
181 183
182#test_hash_operations_SOURCES = \
183# test_hash_operations.c
184#test_hash_operations_LDADD = \
185# $(top_builddir)/src/util/libgnunetutil.la \
186# $(top_builddir)/src/testing/libgnunettesting.la \
187# $(top_builddir)/src/dht/libgnunetdht.la
188
189test_dht_twopeer_SOURCES = \ 184test_dht_twopeer_SOURCES = \
190 test_dht_twopeer.c 185 test_dht_twopeer.c
191test_dht_twopeer_LDADD = \ 186test_dht_twopeer_LDADD = \
@@ -201,6 +196,13 @@ test_dht_twopeer_put_get_LDADD = \
201 $(top_builddir)/src/util/libgnunetutil.la \ 196 $(top_builddir)/src/util/libgnunetutil.la \
202 $(top_builddir)/src/testing/libgnunettesting.la \ 197 $(top_builddir)/src/testing/libgnunettesting.la \
203 $(top_builddir)/src/dht/libgnunetdht.la 198 $(top_builddir)/src/dht/libgnunetdht.la
199
200test_dht_twopeer_path_tracking_SOURCES = \
201 test_dht_twopeer_path_tracking.c
202test_dht_twopeer_path_tracking_LDADD = \
203 $(top_builddir)/src/util/libgnunetutil.la \
204 $(top_builddir)/src/testing/libgnunettesting.la \
205 $(top_builddir)/src/dht/libgnunetdht.la
204 206
205test_dhtlog_SOURCES = \ 207test_dhtlog_SOURCES = \
206 test_dhtlog.c 208 test_dhtlog.c
diff --git a/src/dht/dht.h b/src/dht/dht.h
index 4e8782bb5..1ea888093 100644
--- a/src/dht/dht.h
+++ b/src/dht/dht.h
@@ -199,18 +199,11 @@ struct GNUNET_DHT_RouteResultMessage
199 struct GNUNET_MessageHeader header; 199 struct GNUNET_MessageHeader header;
200 200
201 /** 201 /**
202 * Number of peers recorded in the "PUT" path. 202 * Number of peers recorded in the outgoing
203 * (original path message took during "PUT"). These 203 * path from source to the final destination
204 * peer identities follow this message. 204 * of this message.
205 */ 205 */
206 uint16_t put_path_length GNUNET_PACKED; 206 uint32_t outgoing_path_length GNUNET_PACKED;
207
208 /**
209 * Number of peers recorded in the "GET" path
210 * (inverse of the path the GET message took). These
211 * peer identities follow this message.
212 */
213 uint16_t get_path_length GNUNET_PACKED;
214 207
215 /** 208 /**
216 * Unique ID identifying this request (necessary for 209 * Unique ID identifying this request (necessary for
@@ -223,11 +216,9 @@ struct GNUNET_DHT_RouteResultMessage
223 */ 216 */
224 GNUNET_HashCode key; 217 GNUNET_HashCode key;
225 218
226 /* PUT path */
227
228 /* GET path */
229
230 /* GNUNET_MessageHeader *enc actual DHT message, copied to end of this dealy do */ 219 /* GNUNET_MessageHeader *enc actual DHT message, copied to end of this dealy do */
220
221 /* OUTGOING path */
231}; 222};
232 223
233 224
@@ -267,11 +258,11 @@ struct GNUNET_DHT_P2PRouteMessage
267 uint32_t network_size GNUNET_PACKED; 258 uint32_t network_size GNUNET_PACKED;
268 259
269 /** 260 /**
270 * Route path length; number of GNUNET_PeerIdentity's 261 * Generic route path length for a message in the
271 * copied to the end of this message (before the actual 262 * DHT that arrived at a peer and generated
272 * encapsulated message) 263 * a reply. Copied to the end of this message.
273 */ 264 */
274 uint32_t route_path_length GNUNET_PACKED; 265 uint32_t outgoing_path_length GNUNET_PACKED;
275 266
276 /** 267 /**
277 * Unique ID identifying this request 268 * Unique ID identifying this request
@@ -290,6 +281,8 @@ struct GNUNET_DHT_P2PRouteMessage
290 281
291 /* GNUNET_MessageHeader *enc actual DHT message, copied to end of this dealy do */ 282 /* GNUNET_MessageHeader *enc actual DHT message, copied to end of this dealy do */
292 283
284 /* OUTGOING PATH */
285
293}; 286};
294 287
295/** 288/**
@@ -307,7 +300,7 @@ struct GNUNET_DHT_P2PRouteResultMessage
307 * (inverse of the path the outgoing message took). 300 * (inverse of the path the outgoing message took).
308 * These peer identities follow this message. 301 * These peer identities follow this message.
309 */ 302 */
310 uint16_t outgoing_path_length GNUNET_PACKED; 303 uint32_t outgoing_path_length GNUNET_PACKED;
311 304
312 /** 305 /**
313 * Message options 306 * Message options
@@ -341,12 +334,9 @@ struct GNUNET_DHT_P2PRouteResultMessage
341 uint32_t network_size GNUNET_PACKED; 334 uint32_t network_size GNUNET_PACKED;
342#endif 335#endif
343 336
344
345 /* PUT path */
346
347 /* GET path */
348
349 /* GNUNET_MessageHeader *enc actual DHT message, copied to end of this dealy do */ 337 /* GNUNET_MessageHeader *enc actual DHT message, copied to end of this dealy do */
338
339 /* OUTGOING PATH */
350}; 340};
351 341
352 342
@@ -449,7 +439,13 @@ struct GNUNET_DHT_GetResultMessage
449 /** 439 /**
450 * The type for the data for the GET request 440 * The type for the data for the GET request
451 */ 441 */
452 uint32_t type; 442 uint16_t type;
443
444 /**
445 * The number of peer identities appended to the end of this
446 * message.
447 */
448 uint16_t put_path_length;
453 449
454 /** 450 /**
455 * When does this entry expire? 451 * When does this entry expire?
@@ -458,5 +454,27 @@ struct GNUNET_DHT_GetResultMessage
458 454
459}; 455};
460 456
457/**
458 * Entry for inserting data into datacache from the DHT.
459 * Needed here so block library can verify entries that
460 * are shoveled into the DHT.
461 */
462struct DHTPutEntry
463{
464 /**
465 * Size of data.
466 */
467 uint16_t data_size;
468
469 /**
470 * Length of recorded path.
471 */
472 uint16_t path_length;
473
474 /* PUT DATA */
475
476 /* PATH ENTRIES */
477};
478
461 479
462#endif /* DHT_H_ */ 480#endif /* DHT_H_ */
diff --git a/src/dht/dht_api.c b/src/dht/dht_api.c
index 285ec1a30..c65699d7a 100644
--- a/src/dht/dht_api.c
+++ b/src/dht/dht_api.c
@@ -182,6 +182,17 @@ struct GNUNET_DHT_Handle
182 struct GNUNET_CONTAINER_MultiHashMap *active_requests; 182 struct GNUNET_CONTAINER_MultiHashMap *active_requests;
183 183
184 /** 184 /**
185 * Task for trying to reconnect.
186 */
187 GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
188
189 /**
190 * How quickly should we retry? Used for exponential back-off on
191 * connect-errors.
192 */
193 struct GNUNET_TIME_Relative retry_time;
194
195 /**
185 * Generator for unique ids. 196 * Generator for unique ids.
186 */ 197 */
187 uint64_t uid_gen; 198 uint64_t uid_gen;
@@ -266,31 +277,62 @@ add_request_to_pending (void *cls,
266 277
267 278
268/** 279/**
269 * Re-connect to the DHT, re-issue all pending requests if needed. 280 * Try reconnecting to the dht service.
281 *
282 * @param cls GNUNET_DHT_Handle
283 * @param tc scheduler context
270 */ 284 */
271static void 285static void
272reconnect (struct GNUNET_DHT_Handle *handle) 286try_reconnect (void *cls,
287 const struct GNUNET_SCHEDULER_TaskContext *tc)
273{ 288{
274 if (handle->client != NULL) 289 struct GNUNET_DHT_Handle *handle = cls;
290
291 if (handle->retry_time.rel_value < GNUNET_CONSTANTS_SERVICE_RETRY.rel_value)
292 handle->retry_time = GNUNET_CONSTANTS_SERVICE_RETRY;
293 else
294 handle->retry_time = GNUNET_TIME_relative_multiply (handle->retry_time, 2);
295 if (handle->retry_time.rel_value > GNUNET_CONSTANTS_SERVICE_TIMEOUT.rel_value)
296 handle->retry_time = GNUNET_CONSTANTS_SERVICE_TIMEOUT;
297 handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
298 handle->client = GNUNET_CLIENT_connect ("dht", handle->cfg);
299 if (handle->client == NULL)
275 { 300 {
276 GNUNET_CLIENT_disconnect (handle->client, 301 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
277 GNUNET_NO); 302 "dht reconnect failed(!)\n");
278 handle->client = NULL; 303 return;
279 } 304 }
280 if (GNUNET_YES != try_connect (handle)) 305
281 return;
282 GNUNET_CONTAINER_multihashmap_iterate (handle->active_requests, 306 GNUNET_CONTAINER_multihashmap_iterate (handle->active_requests,
283 &add_request_to_pending, 307 &add_request_to_pending,
284 handle); 308 handle);
285 if (handle->pending_head == NULL) 309 if (handle->pending_head == NULL)
286 return; 310 return;
287 GNUNET_CLIENT_notify_transmit_ready (handle->client, 311 GNUNET_CLIENT_notify_transmit_ready (handle->client,
288 ntohs(handle->pending_head->msg->size), 312 ntohs(handle->pending_head->msg->size),
289 GNUNET_TIME_UNIT_FOREVER_REL, 313 GNUNET_TIME_UNIT_FOREVER_REL,
290 GNUNET_NO, 314 GNUNET_NO,
291 &transmit_pending, 315 &transmit_pending,
292 handle); 316 handle);
293 317}
318
319
320/**
321 * Try reconnecting to the DHT service.
322 *
323 * @param handle handle to dht to (possibly) disconnect and reconnect
324 */
325static void
326do_disconnect (struct GNUNET_DHT_Handle *handle)
327{
328 if (handle->client == NULL)
329 return;
330
331 GNUNET_CLIENT_disconnect (handle->client, GNUNET_NO);
332 handle->client = NULL;
333 handle->reconnect_task = GNUNET_SCHEDULER_add_delayed (handle->retry_time,
334 &try_reconnect,
335 handle);
294} 336}
295 337
296 338
@@ -302,8 +344,11 @@ process_pending_messages (struct GNUNET_DHT_Handle *handle)
302{ 344{
303 struct PendingMessage *head; 345 struct PendingMessage *head;
304 346
305 if (GNUNET_YES != try_connect (handle)) 347 if (handle->client == NULL)
306 return; 348 {
349 do_disconnect(handle);
350 return;
351 }
307 if (handle->th != NULL) 352 if (handle->th != NULL)
308 return; 353 return;
309 if (NULL == (head = handle->pending_head)) 354 if (NULL == (head = handle->pending_head))
@@ -316,7 +361,7 @@ process_pending_messages (struct GNUNET_DHT_Handle *handle)
316 handle); 361 handle);
317 if (NULL == handle->th) 362 if (NULL == handle->th)
318 { 363 {
319 reconnect (handle); 364 do_disconnect (handle);
320 return; 365 return;
321 } 366 }
322} 367}
@@ -337,7 +382,7 @@ transmit_pending (void *cls,
337 handle->th = NULL; 382 handle->th = NULL;
338 if (buf == NULL) 383 if (buf == NULL)
339 { 384 {
340 reconnect (handle); 385 do_disconnect (handle);
341 return 0; 386 return 0;
342 } 387 }
343 if (NULL == (head = handle->pending_head)) 388 if (NULL == (head = handle->pending_head))
@@ -377,8 +422,6 @@ transmit_pending (void *cls,
377} 422}
378 423
379 424
380
381
382/** 425/**
383 * Process a given reply that might match the given 426 * Process a given reply that might match the given
384 * request. 427 * request.
@@ -393,12 +436,11 @@ process_reply (void *cls,
393 const struct GNUNET_MessageHeader *enc_msg; 436 const struct GNUNET_MessageHeader *enc_msg;
394 size_t enc_size; 437 size_t enc_size;
395 uint64_t uid; 438 uint64_t uid;
396 const struct GNUNET_PeerIdentity **get_path; 439 const struct GNUNET_PeerIdentity **outgoing_path;
397 const struct GNUNET_PeerIdentity **put_path;
398 const struct GNUNET_PeerIdentity *pos; 440 const struct GNUNET_PeerIdentity *pos;
399 uint16_t gpl; 441 uint32_t outgoing_path_length;
400 uint16_t ppl;
401 unsigned int i; 442 unsigned int i;
443 char *path_offset;
402 444
403 uid = GNUNET_ntohll (dht_msg->unique_id); 445 uid = GNUNET_ntohll (dht_msg->unique_id);
404 if (uid != rh->uid) 446 if (uid != rh->uid)
@@ -407,62 +449,43 @@ process_reply (void *cls,
407 "Reply UID did not match request UID\n"); 449 "Reply UID did not match request UID\n");
408 return GNUNET_YES; 450 return GNUNET_YES;
409 } 451 }
410 enc_size = ntohs (dht_msg->header.size) - sizeof (struct GNUNET_DHT_RouteResultMessage); 452 enc_msg = (const struct GNUNET_MessageHeader *)&dht_msg[1];
453 enc_size = ntohs (enc_msg->size);
411 if (enc_size < sizeof (struct GNUNET_MessageHeader)) 454 if (enc_size < sizeof (struct GNUNET_MessageHeader))
412 { 455 {
413 GNUNET_break (0); 456 GNUNET_break (0);
414 return GNUNET_NO; 457 return GNUNET_NO;
415 } 458 }
416 pos = (const struct GNUNET_PeerIdentity *) &dht_msg[1]; 459 path_offset = (char *)&dht_msg[1];
417 ppl = ntohs (dht_msg->put_path_length); 460 path_offset += enc_size;
418 gpl = ntohs (dht_msg->get_path_length); 461 pos = (const struct GNUNET_PeerIdentity *) path_offset;
419 if ( (ppl + gpl) * sizeof (struct GNUNET_PeerIdentity) > enc_size) 462 outgoing_path_length = ntohl (dht_msg->outgoing_path_length);
463 if (outgoing_path_length * sizeof (struct GNUNET_PeerIdentity) > ntohs(dht_msg->header.size) - enc_size)
420 { 464 {
421 GNUNET_break (0); 465 GNUNET_break (0);
422 return GNUNET_NO; 466 return GNUNET_NO;
423 } 467 }
424 if (ppl > 0) 468
425 { 469 if (outgoing_path_length > 0)
426 put_path = GNUNET_malloc ((ppl+1) * sizeof (struct GNUNET_PeerIdentity*));
427 for (i=0;i<ppl;i++)
428 {
429 put_path[i] = pos;
430 pos++;
431 }
432 put_path[ppl] = NULL;
433 }
434 else
435 put_path = NULL;
436 if (gpl > 0)
437 { 470 {
438 get_path = GNUNET_malloc ((gpl+1) * sizeof (struct GNUNET_PeerIdentity*)); 471 outgoing_path = GNUNET_malloc ((outgoing_path_length + 1) * sizeof (struct GNUNET_PeerIdentity*));
439 for (i=0;i<gpl;i++) 472 for (i = 0; i < outgoing_path_length; i++)
440 { 473 {
441 get_path[i] = pos; 474 outgoing_path[i] = pos;
442 pos++; 475 pos++;
443 } 476 }
444 get_path[gpl] = NULL; 477 outgoing_path[outgoing_path_length] = NULL;
445 } 478 }
446 else 479 else
447 get_path = NULL; 480 outgoing_path = NULL;
448 enc_size -= (ppl + gpl) * sizeof (struct GNUNET_PeerIdentity); 481
449 enc_msg = (const struct GNUNET_MessageHeader *) pos;
450 if (enc_size != ntohs (enc_msg->size))
451 {
452 GNUNET_break (0);
453 GNUNET_free_non_null (get_path);
454 GNUNET_free_non_null (put_path);
455 return GNUNET_NO;
456 }
457 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 482 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
458 "Processing reply.\n"); 483 "Processing reply.\n");
459 rh->iter (rh->iter_cls, 484 rh->iter (rh->iter_cls,
460 &rh->key, 485 &rh->key,
461 get_path, 486 outgoing_path,
462 put_path,
463 enc_msg); 487 enc_msg);
464 GNUNET_free_non_null (get_path); 488 GNUNET_free_non_null (outgoing_path);
465 GNUNET_free_non_null (put_path);
466 return GNUNET_YES; 489 return GNUNET_YES;
467} 490}
468 491
@@ -485,19 +508,19 @@ service_message_handler (void *cls,
485 { 508 {
486 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 509 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
487 "Error receiving data from DHT service, reconnecting\n"); 510 "Error receiving data from DHT service, reconnecting\n");
488 reconnect (handle); 511 do_disconnect (handle);
489 return; 512 return;
490 } 513 }
491 if (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_DHT_LOCAL_ROUTE_RESULT) 514 if (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_DHT_LOCAL_ROUTE_RESULT)
492 { 515 {
493 GNUNET_break (0); 516 GNUNET_break (0);
494 reconnect (handle); 517 do_disconnect (handle);
495 return; 518 return;
496 } 519 }
497 if (ntohs (msg->size) < sizeof (struct GNUNET_DHT_RouteResultMessage)) 520 if (ntohs (msg->size) < sizeof (struct GNUNET_DHT_RouteResultMessage))
498 { 521 {
499 GNUNET_break (0); 522 GNUNET_break (0);
500 reconnect (handle); 523 do_disconnect (handle);
501 return; 524 return;
502 } 525 }
503 dht_msg = (const struct GNUNET_DHT_RouteResultMessage *) msg; 526 dht_msg = (const struct GNUNET_DHT_RouteResultMessage *) msg;
diff --git a/src/dht/dht_api_find_peer.c b/src/dht/dht_api_find_peer.c
index cd3bed5ba..8196e394c 100644
--- a/src/dht/dht_api_find_peer.c
+++ b/src/dht/dht_api_find_peer.c
@@ -65,17 +65,15 @@ struct GNUNET_DHT_FindPeerHandle
65 * 65 *
66 * @param cls closure 66 * @param cls closure
67 * @param key key that was used 67 * @param key key that was used
68 * @param get_path NULL-terminated array of pointers 68 * @param outgoing_path NULL-terminated array of pointers
69 * to the peers on reverse GET path (or NULL if not recorded) 69 * to the peers on reverse path
70 * @param put_path NULL-terminated array of pointers 70 * (or NULL if not recorded)
71 * to the peers on the PUT path (or NULL if not recorded)
72 * @param reply response 71 * @param reply response
73 */ 72 */
74static void 73static void
75find_peer_reply_iterator (void *cls, 74find_peer_reply_iterator (void *cls,
76 const GNUNET_HashCode *key, 75 const GNUNET_HashCode *key,
77 const struct GNUNET_PeerIdentity * const *get_path, 76 const struct GNUNET_PeerIdentity * const *outgoing_path,
78 const struct GNUNET_PeerIdentity * const *put_path,
79 const struct GNUNET_MessageHeader *reply) 77 const struct GNUNET_MessageHeader *reply)
80{ 78{
81 struct GNUNET_DHT_FindPeerHandle *find_peer_handle = cls; 79 struct GNUNET_DHT_FindPeerHandle *find_peer_handle = cls;
diff --git a/src/dht/dht_api_get_put.c b/src/dht/dht_api_get_put.c
index 3b7a6d83a..5b5baa531 100644
--- a/src/dht/dht_api_get_put.c
+++ b/src/dht/dht_api_get_put.c
@@ -124,22 +124,25 @@ struct GNUNET_DHT_GetHandle
124 * 124 *
125 * @param cls the 'struct GNUNET_DHT_GetHandle' 125 * @param cls the 'struct GNUNET_DHT_GetHandle'
126 * @param key key that was used 126 * @param key key that was used
127 * @param get_path NULL-terminated array of pointers 127 * @param outgoing_path path of the message from this peer
128 * to the peers on reverse GET path (or NULL if not recorded) 128 * to the target
129 * @param put_path NULL-terminated array of pointers
130 * to the peers on the PUT path (or NULL if not recorded)
131 * @param reply response 129 * @param reply response
132 */ 130 */
133static void 131static void
134get_reply_iterator (void *cls, 132get_reply_iterator (void *cls,
135 const GNUNET_HashCode *key, 133 const GNUNET_HashCode *key,
136 const struct GNUNET_PeerIdentity * const *get_path, 134 const struct GNUNET_PeerIdentity * const *outgoing_path,
137 const struct GNUNET_PeerIdentity * const *put_path,
138 const struct GNUNET_MessageHeader *reply) 135 const struct GNUNET_MessageHeader *reply)
139{ 136{
140 struct GNUNET_DHT_GetHandle *get_handle = cls; 137 struct GNUNET_DHT_GetHandle *get_handle = cls;
141 const struct GNUNET_DHT_GetResultMessage *result; 138 const struct GNUNET_DHT_GetResultMessage *result;
139 const struct GNUNET_PeerIdentity **put_path;
142 size_t payload; 140 size_t payload;
141 char *path_offset;
142 const struct GNUNET_PeerIdentity *pos;
143 unsigned int i;
144 uint16_t put_path_length;
145 uint16_t data_size;
143 146
144 if (ntohs (reply->type) != GNUNET_MESSAGE_TYPE_DHT_GET_RESULT) 147 if (ntohs (reply->type) != GNUNET_MESSAGE_TYPE_DHT_GET_RESULT)
145 { 148 {
@@ -150,15 +153,36 @@ get_reply_iterator (void *cls,
150 GNUNET_assert (ntohs (reply->size) >= 153 GNUNET_assert (ntohs (reply->size) >=
151 sizeof (struct GNUNET_DHT_GetResultMessage)); 154 sizeof (struct GNUNET_DHT_GetResultMessage));
152 result = (const struct GNUNET_DHT_GetResultMessage *) reply; 155 result = (const struct GNUNET_DHT_GetResultMessage *) reply;
156
157 put_path = NULL;
158 put_path_length = ntohs(result->put_path_length);
159 if (put_path_length > 0)
160 {
161 data_size = ntohs(result->header.size) - (put_path_length * sizeof(struct GNUNET_PeerIdentity)) - sizeof(struct GNUNET_DHT_GetResultMessage);
162 path_offset = (char *)&result[1];
163 //GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "In get_reply_iterator, result->header.size is %d, put_path_length %d, offset is %d, data_size is %d\n", ntohs(result->header.size), put_path_length, ntohs(result->header.size) - (put_path_length * sizeof(struct GNUNET_PeerIdentity)), data_size);
164 path_offset += data_size;
165 pos = (const struct GNUNET_PeerIdentity *)path_offset;
166 //GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Found put peer %s\n", GNUNET_i2s((const struct GNUNET_PeerIdentity *)path_offset));
167 put_path = GNUNET_malloc ((put_path_length + 1) * sizeof (struct GNUNET_PeerIdentity*));
168 for (i = 0; i < put_path_length; i++)
169 {
170 put_path[i] = pos;
171 pos++;
172 }
173 put_path[put_path_length] = NULL;
174 }
175
153 payload = ntohs (reply->size) - sizeof(struct GNUNET_DHT_GetResultMessage); 176 payload = ntohs (reply->size) - sizeof(struct GNUNET_DHT_GetResultMessage);
154 get_handle->iter (get_handle->iter_cls, 177 get_handle->iter (get_handle->iter_cls,
155 GNUNET_TIME_absolute_ntoh (result->expiration), 178 GNUNET_TIME_absolute_ntoh (result->expiration),
156 key, 179 key,
157 get_path, 180 outgoing_path,
158 put_path, 181 put_path,
159 ntohs (result->type), 182 ntohs (result->type),
160 payload, 183 payload,
161 &result[1]); 184 &result[1]);
185 GNUNET_free_non_null(put_path);
162} 186}
163 187
164 188
diff --git a/src/dht/gnunet-service-dht.c b/src/dht/gnunet-service-dht.c
index b8f7e4732..2f5be7691 100644
--- a/src/dht/gnunet-service-dht.c
+++ b/src/dht/gnunet-service-dht.c
@@ -1096,6 +1096,10 @@ forward_result_message (const struct GNUNET_MessageHeader *msg,
1096 size_t msize; 1096 size_t msize;
1097 size_t psize; 1097 size_t psize;
1098 char *path_start; 1098 char *path_start;
1099 char *path_offset;
1100#if DEBUG_PATH
1101 unsigned int i;
1102#endif
1099 1103
1100 increment_stats (STAT_RESULT_FORWARDS); 1104 increment_stats (STAT_RESULT_FORWARDS);
1101 msize = 1105 msize =
@@ -1118,6 +1122,13 @@ forward_result_message (const struct GNUNET_MessageHeader *msg,
1118 /* Offset by the size of the enc_msg */ 1122 /* Offset by the size of the enc_msg */
1119 path_start += ntohs (msg->size); 1123 path_start += ntohs (msg->size);
1120 memcpy(path_start, msg_ctx->path_history, msg_ctx->path_history_len * (sizeof(struct GNUNET_PeerIdentity))); 1124 memcpy(path_start, msg_ctx->path_history, msg_ctx->path_history_len * (sizeof(struct GNUNET_PeerIdentity)));
1125#if DEBUG_PATH
1126 for (i = 0; i < msg_ctx->path_history_len; i++)
1127 {
1128 path_offset = &msg_ctx->path_history[i * sizeof(struct GNUNET_PeerIdentity)];
1129 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "(forward_result) Key %s Found peer %d:%s\n", GNUNET_h2s(&msg_ctx->key), i, GNUNET_i2s((struct GNUNET_PeerIdentity *)path_offset));
1130 }
1131#endif
1121 } 1132 }
1122 result_message->options = htonl (msg_ctx->msg_options); 1133 result_message->options = htonl (msg_ctx->msg_options);
1123 result_message->hop_count = htonl (msg_ctx->hop_count + 1); 1134 result_message->hop_count = htonl (msg_ctx->hop_count + 1);
@@ -1128,7 +1139,13 @@ forward_result_message (const struct GNUNET_MessageHeader *msg,
1128 DHT_BLOOM_SIZE)); 1139 DHT_BLOOM_SIZE));
1129 result_message->unique_id = GNUNET_htonll (msg_ctx->unique_id); 1140 result_message->unique_id = GNUNET_htonll (msg_ctx->unique_id);
1130 memcpy (&result_message->key, &msg_ctx->key, sizeof (GNUNET_HashCode)); 1141 memcpy (&result_message->key, &msg_ctx->key, sizeof (GNUNET_HashCode));
1142 /* Copy the enc_msg, then the path history as well! */
1131 memcpy (&result_message[1], msg, ntohs (msg->size)); 1143 memcpy (&result_message[1], msg, ntohs (msg->size));
1144 path_offset = (char *)&result_message[1];
1145 path_offset += ntohs (msg->size);
1146 /* If we have path history, copy it to the end of the whole thing */
1147 if (msg_ctx->path_history_len > 0)
1148 memcpy(path_offset, msg_ctx->path_history, msg_ctx->path_history_len * (sizeof(struct GNUNET_PeerIdentity)));
1132#if DEBUG_DHT > 1 1149#if DEBUG_DHT > 1
1133 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1150 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1134 "%s:%s Adding pending message size %d for peer %s\n", 1151 "%s:%s Adding pending message size %d for peer %s\n",
@@ -1774,7 +1791,7 @@ forward_message (const struct GNUNET_MessageHeader *msg,
1774 memcpy (&route_message[1], msg, ntohs (msg->size)); 1791 memcpy (&route_message[1], msg, ntohs (msg->size));
1775 if (GNUNET_DHT_RO_RECORD_ROUTE == (msg_ctx->msg_options & GNUNET_DHT_RO_RECORD_ROUTE)) 1792 if (GNUNET_DHT_RO_RECORD_ROUTE == (msg_ctx->msg_options & GNUNET_DHT_RO_RECORD_ROUTE))
1776 { 1793 {
1777 route_message->route_path_length = htonl(msg_ctx->path_history_len); 1794 route_message->outgoing_path_length = htonl(msg_ctx->path_history_len);
1778 /* Set pointer to start of enc_msg */ 1795 /* Set pointer to start of enc_msg */
1779 route_path = (char *)&route_message[1]; 1796 route_path = (char *)&route_message[1];
1780 /* Offset to the end of the enc_msg */ 1797 /* Offset to the end of the enc_msg */
@@ -1992,18 +2009,23 @@ add_pending_message (struct ClientList *client,
1992static void 2009static void
1993send_reply_to_client (struct ClientList *client, 2010send_reply_to_client (struct ClientList *client,
1994 const struct GNUNET_MessageHeader *message, 2011 const struct GNUNET_MessageHeader *message,
1995 unsigned long long uid, const GNUNET_HashCode * key) 2012 struct DHT_MessageContext *msg_ctx)
1996{ 2013{
1997 struct GNUNET_DHT_RouteResultMessage *reply; 2014 struct GNUNET_DHT_RouteResultMessage *reply;
1998 struct PendingMessage *pending_message; 2015 struct PendingMessage *pending_message;
1999 uint16_t msize; 2016 uint16_t msize;
2000 size_t tsize; 2017 size_t tsize;
2018 char *reply_offset;
2019#if DEBUG_PATH
2020 char *path_offset;
2021 unsigned int i;
2022#endif
2001#if DEBUG_DHT 2023#if DEBUG_DHT
2002 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2024 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2003 "`%s:%s': Sending reply to client.\n", my_short_id, "DHT"); 2025 "`%s:%s': Sending reply to client.\n", my_short_id, "DHT");
2004#endif 2026#endif
2005 msize = ntohs (message->size); 2027 msize = ntohs (message->size);
2006 tsize = sizeof (struct GNUNET_DHT_RouteResultMessage) + msize; 2028 tsize = sizeof (struct GNUNET_DHT_RouteResultMessage) + msize + (msg_ctx->path_history_len * sizeof(struct GNUNET_PeerIdentity));
2007 if (tsize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) 2029 if (tsize >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
2008 { 2030 {
2009 GNUNET_break_op (0); 2031 GNUNET_break_op (0);
@@ -2014,11 +2036,24 @@ send_reply_to_client (struct ClientList *client,
2014 reply = (struct GNUNET_DHT_RouteResultMessage *) &pending_message[1]; 2036 reply = (struct GNUNET_DHT_RouteResultMessage *) &pending_message[1];
2015 reply->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_LOCAL_ROUTE_RESULT); 2037 reply->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_LOCAL_ROUTE_RESULT);
2016 reply->header.size = htons (tsize); 2038 reply->header.size = htons (tsize);
2017 reply->put_path_length = htons (0); /* FIXME: implement */ 2039 reply->outgoing_path_length = htonl(msg_ctx->path_history_len);
2018 reply->get_path_length = htons (0); /* FIXME: implement */ 2040 reply->unique_id = GNUNET_htonll (msg_ctx->unique_id);
2019 reply->unique_id = GNUNET_htonll (uid); 2041 memcpy (&reply->key, &msg_ctx->key, sizeof (GNUNET_HashCode));
2020 reply->key = *key; 2042 reply_offset = (char *)&reply[1];
2021 memcpy (&reply[1], message, msize); 2043 memcpy (&reply[1], message, msize);
2044 if (msg_ctx->path_history_len > 0)
2045 {
2046 reply_offset += msize;
2047 memcpy(reply_offset, msg_ctx->path_history, msg_ctx->path_history_len * sizeof(struct GNUNET_PeerIdentity));
2048 }
2049#if DEBUG_PATH
2050 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Returning message with outgoing path length %d\n", msg_ctx->path_history_len);
2051 for (i = 0; i < msg_ctx->path_history_len; i++)
2052 {
2053 path_offset = &msg_ctx->path_history[i * sizeof(struct GNUNET_PeerIdentity)];
2054 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Found peer %d:%s\n", i, GNUNET_i2s((struct GNUNET_PeerIdentity *)path_offset));
2055 }
2056#endif
2022 add_pending_message (client, pending_message); 2057 add_pending_message (client, pending_message);
2023} 2058}
2024 2059
@@ -2105,6 +2140,8 @@ route_result_message (struct GNUNET_MessageHeader *msg,
2105 struct DHTRouteSource *pos; 2140 struct DHTRouteSource *pos;
2106 struct PeerInfo *peer_info; 2141 struct PeerInfo *peer_info;
2107 const struct GNUNET_MessageHeader *hello_msg; 2142 const struct GNUNET_MessageHeader *hello_msg;
2143 unsigned int i;
2144 char *path_offset;
2108 2145
2109 increment_stats (STAT_RESULTS); 2146 increment_stats (STAT_RESULTS);
2110 /** 2147 /**
@@ -2221,8 +2258,12 @@ route_result_message (struct GNUNET_MessageHeader *msg,
2221 if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_DHT_GET_RESULT) 2258 if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_DHT_GET_RESULT)
2222 increment_stats (STAT_GET_REPLY); 2259 increment_stats (STAT_GET_REPLY);
2223 2260
2224 send_reply_to_client (pos->client, msg, 2261 for (i = 0; i < msg_ctx->path_history_len; i++)
2225 msg_ctx->unique_id, &msg_ctx->key); 2262 {
2263 path_offset = &msg_ctx->path_history[i * sizeof(struct GNUNET_PeerIdentity)];
2264 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "(before client) Key %s Found peer %d:%s\n", GNUNET_h2s(&msg_ctx->key), i, GNUNET_i2s((struct GNUNET_PeerIdentity *)path_offset));
2265 }
2266 send_reply_to_client (pos->client, msg, msg_ctx);
2226 } 2267 }
2227 else /* Send to peer */ 2268 else /* Send to peer */
2228 { 2269 {
@@ -2313,6 +2354,12 @@ datacache_get_iterator (void *cls,
2313 struct DHT_MessageContext *new_msg_ctx; 2354 struct DHT_MessageContext *new_msg_ctx;
2314 struct GNUNET_DHT_GetResultMessage *get_result; 2355 struct GNUNET_DHT_GetResultMessage *get_result;
2315 enum GNUNET_BLOCK_EvaluationResult eval; 2356 enum GNUNET_BLOCK_EvaluationResult eval;
2357 const struct DHTPutEntry *put_entry;
2358 int get_size;
2359 char *path_offset;
2360#if DEBUG_PATH
2361 unsigned int i;
2362#endif
2316 2363
2317#if DEBUG_DHT 2364#if DEBUG_DHT
2318 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2365 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -2326,6 +2373,24 @@ datacache_get_iterator (void *cls,
2326 msg_ctx->reply_bf_mutator, 2373 msg_ctx->reply_bf_mutator,
2327 msg_ctx->xquery, 2374 msg_ctx->xquery,
2328 msg_ctx->xquery_size, data, size); 2375 msg_ctx->xquery_size, data, size);
2376
2377 put_entry = (const struct DHTPutEntry *)data;
2378
2379 if (size != sizeof(struct DHTPutEntry) +
2380 put_entry->data_size +
2381 (put_entry->path_length * sizeof(struct GNUNET_PeerIdentity)))
2382 {
2383 GNUNET_log(
2384 GNUNET_ERROR_TYPE_WARNING,
2385 "Path + data size doesn't add up for data inserted into datacache!\nData size %d, path length %d, expected %d, got %d\n",
2386 put_entry->data_size, put_entry->path_length,
2387 sizeof(struct DHTPutEntry) + put_entry->data_size
2388 + (put_entry->path_length * sizeof(struct GNUNET_PeerIdentity)),
2389 size);
2390 msg_ctx->do_forward = GNUNET_NO;
2391 return GNUNET_OK;
2392 }
2393
2329 switch (eval) 2394 switch (eval)
2330 { 2395 {
2331 case GNUNET_BLOCK_EVALUATION_OK_LAST: 2396 case GNUNET_BLOCK_EVALUATION_OK_LAST:
@@ -2339,15 +2404,32 @@ datacache_get_iterator (void *cls,
2339 new_msg_ctx->path_history_len = msg_ctx->path_history_len; 2404 new_msg_ctx->path_history_len = msg_ctx->path_history_len;
2340 /* Assign to previous msg_ctx path history, caller should free after our return */ 2405 /* Assign to previous msg_ctx path history, caller should free after our return */
2341 new_msg_ctx->path_history = msg_ctx->path_history; 2406 new_msg_ctx->path_history = msg_ctx->path_history;
2407#if DEBUG_PATH
2408 for (i = 0; i < new_msg_ctx->path_history_len; i++)
2409 {
2410 path_offset = &new_msg_ctx->path_history[i * sizeof(struct GNUNET_PeerIdentity)];
2411 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "(get_iterator) Key %s Found peer %d:%s\n", GNUNET_h2s(&msg_ctx->key), i, GNUNET_i2s((struct GNUNET_PeerIdentity *)path_offset));
2412 }
2413#endif
2342 } 2414 }
2343 get_result = 2415
2344 GNUNET_malloc (sizeof (struct GNUNET_DHT_GetResultMessage) + size); 2416 get_size = sizeof (struct GNUNET_DHT_GetResultMessage) + put_entry->data_size + (put_entry->path_length * sizeof(struct GNUNET_PeerIdentity));
2417 get_result = GNUNET_malloc (get_size);
2345 get_result->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_GET_RESULT); 2418 get_result->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_GET_RESULT);
2346 get_result->header.size = 2419 get_result->header.size = htons (get_size);
2347 htons (sizeof (struct GNUNET_DHT_GetResultMessage) + size);
2348 get_result->expiration = GNUNET_TIME_absolute_hton (exp); 2420 get_result->expiration = GNUNET_TIME_absolute_hton (exp);
2349 get_result->type = htons (type); 2421 get_result->type = htons (type);
2350 memcpy (&get_result[1], data, size); 2422 get_result->put_path_length = htons(put_entry->path_length);
2423 path_offset = (char *)&put_entry[1];
2424 path_offset += put_entry->data_size;
2425#if DEBUG_PATH
2426 for (i = 0; i < put_entry->path_length; i++)
2427 {
2428 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "(get_iterator PUT path) Key %s Found peer %d:%s\n", GNUNET_h2s(&msg_ctx->key), i, GNUNET_i2s((struct GNUNET_PeerIdentity *)&path_offset[i * sizeof(struct GNUNET_PeerIdentity)]));
2429 }
2430#endif
2431 /* Copy the actual data and the path_history to the end of the get result */
2432 memcpy (&get_result[1], &put_entry[1], put_entry->data_size + (put_entry->path_length * sizeof(struct GNUNET_PeerIdentity)));
2351 new_msg_ctx->peer = &my_identity; 2433 new_msg_ctx->peer = &my_identity;
2352 new_msg_ctx->bloom = 2434 new_msg_ctx->bloom =
2353 GNUNET_CONTAINER_bloomfilter_init (NULL, DHT_BLOOM_SIZE, DHT_BLOOM_K); 2435 GNUNET_CONTAINER_bloomfilter_init (NULL, DHT_BLOOM_SIZE, DHT_BLOOM_K);
@@ -2367,7 +2449,7 @@ datacache_get_iterator (void *cls,
2367 break; 2449 break;
2368 case GNUNET_BLOCK_EVALUATION_RESULT_INVALID: 2450 case GNUNET_BLOCK_EVALUATION_RESULT_INVALID:
2369#if DEBUG_DHT 2451#if DEBUG_DHT
2370 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2452 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2371 "`%s:%s': Invalid request error\n", my_short_id, "DHT"); 2453 "`%s:%s': Invalid request error\n", my_short_id, "DHT");
2372#endif 2454#endif
2373 break; 2455 break;
@@ -2385,7 +2467,7 @@ datacache_get_iterator (void *cls,
2385 break; 2467 break;
2386 case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED: 2468 case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED:
2387#if DEBUG_DHT 2469#if DEBUG_DHT
2388 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2470 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2389 "`%s:%s': Unsupported block type (%u) in response!\n", 2471 "`%s:%s': Unsupported block type (%u) in response!\n",
2390 my_short_id, "DHT", type); 2472 my_short_id, "DHT", type);
2391#endif 2473#endif
@@ -2781,6 +2863,9 @@ handle_dht_put (const struct GNUNET_MessageHeader *msg,
2781 struct DHT_MessageContext *msg_ctx) 2863 struct DHT_MessageContext *msg_ctx)
2782{ 2864{
2783 const struct GNUNET_DHT_PutMessage *put_msg; 2865 const struct GNUNET_DHT_PutMessage *put_msg;
2866 struct DHTPutEntry *put_entry;
2867 unsigned int put_size;
2868 char *path_offset;
2784 enum GNUNET_BLOCK_Type put_type; 2869 enum GNUNET_BLOCK_Type put_type;
2785 size_t data_size; 2870 size_t data_size;
2786 int ret; 2871 int ret;
@@ -2789,7 +2874,6 @@ handle_dht_put (const struct GNUNET_MessageHeader *msg,
2789 2874
2790 GNUNET_assert (ntohs (msg->size) >= sizeof (struct GNUNET_DHT_PutMessage)); 2875 GNUNET_assert (ntohs (msg->size) >= sizeof (struct GNUNET_DHT_PutMessage));
2791 2876
2792
2793 put_msg = (const struct GNUNET_DHT_PutMessage *) msg; 2877 put_msg = (const struct GNUNET_DHT_PutMessage *) msg;
2794 put_type = (enum GNUNET_BLOCK_Type) ntohl (put_msg->type); 2878 put_type = (enum GNUNET_BLOCK_Type) ntohl (put_msg->type);
2795#if HAVE_MALICIOUS 2879#if HAVE_MALICIOUS
@@ -2897,8 +2981,22 @@ handle_dht_put (const struct GNUNET_MessageHeader *msg,
2897 increment_stats (STAT_PUTS_INSERTED); 2981 increment_stats (STAT_PUTS_INSERTED);
2898 if (datacache != NULL) 2982 if (datacache != NULL)
2899 { 2983 {
2900 ret = GNUNET_DATACACHE_put (datacache, &msg_ctx->key, data_size, 2984 /* Put size is actual data size plus struct overhead plus path length (if any) */
2901 (char *) &put_msg[1], put_type, 2985 put_size = data_size + sizeof(struct DHTPutEntry) + (msg_ctx->path_history_len * sizeof(struct GNUNET_PeerIdentity));
2986 put_entry = GNUNET_malloc(put_size);
2987 put_entry->data_size = data_size;
2988 put_entry->path_length = msg_ctx->path_history_len;
2989 /* Copy data to end of put entry */
2990 memcpy(&put_entry[1], &put_msg[1], data_size);
2991 if (msg_ctx->path_history_len > 0)
2992 {
2993 /* Copy path after data */
2994 path_offset = (char *)&put_entry[1];
2995 path_offset += data_size;
2996 memcpy(path_offset, msg_ctx->path_history, msg_ctx->path_history_len * sizeof(struct GNUNET_PeerIdentity));
2997 }
2998 ret = GNUNET_DATACACHE_put (datacache, &msg_ctx->key, put_size,
2999 (char *) put_entry, put_type,
2902 GNUNET_TIME_absolute_ntoh 3000 GNUNET_TIME_absolute_ntoh
2903 (put_msg->expiration)); 3001 (put_msg->expiration));
2904 3002
@@ -4776,7 +4874,7 @@ handle_dht_p2p_route_request (void *cls,
4776 msg_ctx->msg_options = ntohl (incoming->options); 4874 msg_ctx->msg_options = ntohl (incoming->options);
4777 if (GNUNET_DHT_RO_RECORD_ROUTE == (msg_ctx->msg_options & GNUNET_DHT_RO_RECORD_ROUTE)) 4875 if (GNUNET_DHT_RO_RECORD_ROUTE == (msg_ctx->msg_options & GNUNET_DHT_RO_RECORD_ROUTE))
4778 { 4876 {
4779 path_size = ntohl(incoming->route_path_length) * sizeof(struct GNUNET_PeerIdentity); 4877 path_size = ntohl(incoming->outgoing_path_length) * sizeof(struct GNUNET_PeerIdentity);
4780 GNUNET_assert(ntohs(message->size) == 4878 GNUNET_assert(ntohs(message->size) ==
4781 (sizeof(struct GNUNET_DHT_P2PRouteMessage) + 4879 (sizeof(struct GNUNET_DHT_P2PRouteMessage) +
4782 ntohs(enc_msg->size) + 4880 ntohs(enc_msg->size) +
@@ -4786,7 +4884,7 @@ handle_dht_p2p_route_request (void *cls,
4786 msg_ctx->path_history = GNUNET_malloc(sizeof(struct GNUNET_PeerIdentity) + path_size); 4884 msg_ctx->path_history = GNUNET_malloc(sizeof(struct GNUNET_PeerIdentity) + path_size);
4787 memcpy(msg_ctx->path_history, route_path, path_size); 4885 memcpy(msg_ctx->path_history, route_path, path_size);
4788 memcpy(&msg_ctx->path_history[path_size], &my_identity, sizeof(struct GNUNET_PeerIdentity)); 4886 memcpy(&msg_ctx->path_history[path_size], &my_identity, sizeof(struct GNUNET_PeerIdentity));
4789 msg_ctx->path_history_len = ntohl(incoming->route_path_length) + 1; 4887 msg_ctx->path_history_len = ntohl(incoming->outgoing_path_length) + 1;
4790 } 4888 }
4791 msg_ctx->network_size = ntohl (incoming->network_size); 4889 msg_ctx->network_size = ntohl (incoming->network_size);
4792 msg_ctx->peer = peer; 4890 msg_ctx->peer = peer;
@@ -4829,7 +4927,10 @@ handle_dht_p2p_route_result (void *cls,
4829 struct GNUNET_MessageHeader *enc_msg = 4927 struct GNUNET_MessageHeader *enc_msg =
4830 (struct GNUNET_MessageHeader *) &incoming[1]; 4928 (struct GNUNET_MessageHeader *) &incoming[1];
4831 struct DHT_MessageContext msg_ctx; 4929 struct DHT_MessageContext msg_ctx;
4832 4930#if DEBUG_PATH
4931 char *path_offset;
4932 unsigned int i;
4933#endif
4833 if (ntohs (enc_msg->size) >= GNUNET_SERVER_MAX_MESSAGE_SIZE - 1) 4934 if (ntohs (enc_msg->size) >= GNUNET_SERVER_MAX_MESSAGE_SIZE - 1)
4834 { 4935 {
4835 GNUNET_break_op (0); 4936 GNUNET_break_op (0);
@@ -4871,16 +4972,22 @@ handle_dht_p2p_route_result (void *cls,
4871 if (ntohs(message->size) - sizeof(struct GNUNET_DHT_P2PRouteResultMessage) - ntohs(enc_msg->size) != 4972 if (ntohs(message->size) - sizeof(struct GNUNET_DHT_P2PRouteResultMessage) - ntohs(enc_msg->size) !=
4872 ntohl (incoming->outgoing_path_length) * sizeof(struct GNUNET_PeerIdentity)) 4973 ntohl (incoming->outgoing_path_length) * sizeof(struct GNUNET_PeerIdentity))
4873 { 4974 {
4874 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Return message indicated a path was included, but sizes are wrong!\nTotal message size %d, enc_msg size %d, left over %d, expected %d\n", 4975 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Return message indicated a path was included, but sizes are wrong!\nTotal message size %d, enc_msg size %d, left over %d, expected %d\n",
4875 ntohs(message->size), ntohs(enc_msg->size), 4976 ntohs(message->size), ntohs(enc_msg->size),
4876 ntohs(message->size) - sizeof(struct GNUNET_DHT_P2PRouteResultMessage) - ntohs(enc_msg->size), 4977 ntohs(message->size) - sizeof(struct GNUNET_DHT_P2PRouteResultMessage) - ntohs(enc_msg->size),
4877 ntohl(incoming->outgoing_path_length) * sizeof(struct GNUNET_PeerIdentity)); 4978 ntohl(incoming->outgoing_path_length) * sizeof(struct GNUNET_PeerIdentity));
4878 return GNUNET_NO; 4979 return GNUNET_NO;
4879 } 4980 }
4880
4881 msg_ctx.path_history = (char *)&incoming[1]; 4981 msg_ctx.path_history = (char *)&incoming[1];
4882 msg_ctx.path_history += ntohs(enc_msg->size); 4982 msg_ctx.path_history += ntohs(enc_msg->size);
4883 msg_ctx.path_history_len = ntohl (incoming->outgoing_path_length); 4983 msg_ctx.path_history_len = ntohl (incoming->outgoing_path_length);
4984#if DEBUG_PATH
4985 for (i = 0; i < msg_ctx.path_history_len; i++)
4986 {
4987 path_offset = &msg_ctx.path_history[i * sizeof(struct GNUNET_PeerIdentity)];
4988 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "(handle_p2p_route_result) Key %s Found peer %d:%s\n", GNUNET_h2s(&msg_ctx.key), i, GNUNET_i2s((struct GNUNET_PeerIdentity *)path_offset));
4989 }
4990#endif
4884 } 4991 }
4885 route_result_message (enc_msg, &msg_ctx); 4992 route_result_message (enc_msg, &msg_ctx);
4886 return GNUNET_YES; 4993 return GNUNET_YES;
@@ -5057,7 +5164,7 @@ handle_core_connect (void *cls,
5057 const struct GNUNET_TRANSPORT_ATS_Information *atsi) 5164 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
5058{ 5165{
5059 struct PeerInfo *ret; 5166 struct PeerInfo *ret;
5060 5167 struct DHTPutEntry *put_entry;
5061 /* Check for connect to self message */ 5168 /* Check for connect to self message */
5062 if (0 == memcmp(&my_identity, peer, sizeof(struct GNUNET_PeerIdentity))) 5169 if (0 == memcmp(&my_identity, peer, sizeof(struct GNUNET_PeerIdentity)))
5063 return; 5170 return;
@@ -5079,10 +5186,18 @@ handle_core_connect (void *cls,
5079 } 5186 }
5080 5187
5081 if (datacache != NULL) 5188 if (datacache != NULL)
5082 GNUNET_DATACACHE_put (datacache, &peer->hashPubKey, 5189 {
5083 sizeof (struct GNUNET_PeerIdentity), 5190 put_entry = GNUNET_malloc(sizeof(struct DHTPutEntry) + sizeof (struct GNUNET_PeerIdentity));
5084 (const char *) peer, GNUNET_BLOCK_TYPE_DHT_HELLO, 5191 put_entry->path_length = 0;
5085 GNUNET_TIME_absolute_get_forever ()); 5192 put_entry->data_size = sizeof (struct GNUNET_PeerIdentity);
5193 memcpy(&put_entry[1], peer, sizeof (struct GNUNET_PeerIdentity));
5194 GNUNET_DATACACHE_put (datacache, &peer->hashPubKey,
5195 sizeof(struct DHTPutEntry) + sizeof (struct GNUNET_PeerIdentity),
5196 (char *)put_entry, GNUNET_BLOCK_TYPE_DHT_HELLO,
5197 GNUNET_TIME_absolute_get_forever ());
5198 }
5199 else
5200 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "DHT has no connection to datacache!\n");
5086 ret = try_add_peer (peer, find_current_bucket (&peer->hashPubKey), atsi); 5201 ret = try_add_peer (peer, find_current_bucket (&peer->hashPubKey), atsi);
5087 if (ret != NULL) 5202 if (ret != NULL)
5088 { 5203 {
diff --git a/src/dht/test_dht_api_data.conf b/src/dht/test_dht_api_data.conf
index 24e3bca30..0fd416704 100644
--- a/src/dht/test_dht_api_data.conf
+++ b/src/dht/test_dht_api_data.conf
@@ -5,6 +5,9 @@ DEFAULTCONFIG = test_dht_api_data.conf
5[fs] 5[fs]
6AUTOSTART = NO 6AUTOSTART = NO
7 7
8[resolver]
9AUTOSTART = NO
10
8[datastore-sqlite] 11[datastore-sqlite]
9FILENAME = $SERVICEHOME/datastore/sqlite.db 12FILENAME = $SERVICEHOME/datastore/sqlite.db
10 13
diff --git a/src/dht/test_dht_api_peer1.conf b/src/dht/test_dht_api_peer1.conf
index 597e7af8f..12457a16a 100644
--- a/src/dht/test_dht_api_peer1.conf
+++ b/src/dht/test_dht_api_peer1.conf
@@ -1,6 +1,9 @@
1[fs] 1[fs]
2AUTOSTART = NO 2AUTOSTART = NO
3 3
4[resolver]
5AUTOSTART = NO
6
4[dht] 7[dht]
5DEBUG = NO 8DEBUG = NO
6AUTOSTART = YES 9AUTOSTART = YES
diff --git a/src/dht/test_dht_multipeer.c b/src/dht/test_dht_multipeer.c
index 24618230a..e4d1a7d20 100644
--- a/src/dht/test_dht_multipeer.c
+++ b/src/dht/test_dht_multipeer.c
@@ -53,6 +53,8 @@
53 53
54#define MAX_OUTSTANDING_GETS 10 54#define MAX_OUTSTANDING_GETS 10
55 55
56#define PATH_TRACKING GNUNET_YES
57
56/* Structs */ 58/* Structs */
57 59
58struct TestPutContext 60struct TestPutContext
@@ -206,6 +208,8 @@ static unsigned int total_connections;
206 */ 208 */
207static unsigned int failed_connections; 209static unsigned int failed_connections;
208 210
211enum GNUNET_DHT_RouteOption route_option;
212
209/* Task handle to use to schedule test failure */ 213/* Task handle to use to schedule test failure */
210GNUNET_SCHEDULER_TaskIdentifier die_task; 214GNUNET_SCHEDULER_TaskIdentifier die_task;
211 215
@@ -224,7 +228,6 @@ static double connect_topology_option_modifier = 0.0;
224/* Global return value (0 for success, anything else for failure) */ 228/* Global return value (0 for success, anything else for failure) */
225static int ok; 229static int ok;
226 230
227
228/** 231/**
229 * Check whether peers successfully shut down. 232 * Check whether peers successfully shut down.
230 */ 233 */
@@ -395,13 +398,30 @@ void get_result_iterator (void *cls,
395 struct TestGetContext *test_get = cls; 398 struct TestGetContext *test_get = cls;
396 GNUNET_HashCode search_key; /* Key stored under */ 399 GNUNET_HashCode search_key; /* Key stored under */
397 char original_data[TEST_DATA_SIZE]; /* Made up data to store */ 400 char original_data[TEST_DATA_SIZE]; /* Made up data to store */
398 401 unsigned int i;
399 memset(original_data, test_get->uid, sizeof(original_data)); 402 memset(original_data, test_get->uid, sizeof(original_data));
400 GNUNET_CRYPTO_hash(original_data, TEST_DATA_SIZE, &search_key); 403 GNUNET_CRYPTO_hash(original_data, TEST_DATA_SIZE, &search_key);
401 404
402 if (test_get->succeeded == GNUNET_YES) 405 if (test_get->succeeded == GNUNET_YES)
403 return; /* Get has already been successful, probably ending now */ 406 return; /* Get has already been successful, probably ending now */
404 407
408#if PATH_TRACKING
409 if (put_path != NULL)
410 {
411 fprintf(stderr, "PUT Path: ");
412 for (i = 0; put_path[i] != NULL; i++)
413 fprintf(stderr, "%s%s", i == 0 ? "" : "->", GNUNET_i2s(put_path[i]));
414 fprintf(stderr, "\n");
415 }
416 if (get_path != NULL)
417 {
418 fprintf(stderr, "GET Path: ");
419 for (i = 0; get_path[i] != NULL; i++)
420 fprintf(stderr, "%s%s", i == 0 ? "" : "->", GNUNET_i2s(get_path[i]));
421 fprintf(stderr, "\n");
422 }
423#endif
424
405 if ((0 != memcmp(&search_key, key, sizeof (GNUNET_HashCode))) || (0 != memcmp(original_data, data, sizeof(original_data)))) 425 if ((0 != memcmp(&search_key, key, sizeof (GNUNET_HashCode))) || (0 != memcmp(original_data, data, sizeof(original_data))))
406 { 426 {
407 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Key or data is not the same as was inserted!\n"); 427 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Key or data is not the same as was inserted!\n");
@@ -448,7 +468,7 @@ do_get (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
448 GNUNET_BLOCK_TYPE_TEST, 468 GNUNET_BLOCK_TYPE_TEST,
449 &key, 469 &key,
450 DEFAULT_GET_REPLICATION, 470 DEFAULT_GET_REPLICATION,
451 GNUNET_DHT_RO_NONE, 471 route_option,
452 NULL, 0, 472 NULL, 0,
453 NULL, 0, 473 NULL, 0,
454 &get_result_iterator, 474 &get_result_iterator,
@@ -517,7 +537,7 @@ do_put (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
517 GNUNET_DHT_put(test_put->dht_handle, 537 GNUNET_DHT_put(test_put->dht_handle,
518 &key, 538 &key,
519 DEFAULT_PUT_REPLICATION, 539 DEFAULT_PUT_REPLICATION,
520 GNUNET_DHT_RO_NONE, 540 route_option,
521 GNUNET_BLOCK_TYPE_TEST, 541 GNUNET_BLOCK_TYPE_TEST,
522 sizeof(data), data, 542 sizeof(data), data,
523 GNUNET_TIME_UNIT_FOREVER_ABS, 543 GNUNET_TIME_UNIT_FOREVER_ABS,
@@ -758,6 +778,12 @@ run (void *cls,
758 char * connect_topology_option_str; 778 char * connect_topology_option_str;
759 char * connect_topology_option_modifier_string; 779 char * connect_topology_option_modifier_string;
760 780
781#if PATH_TRACKING
782 route_option = GNUNET_DHT_RO_RECORD_ROUTE;
783#else
784 route_option = GNUNET_DHT_RO_NONE;
785#endif
786
761 /* Get path from configuration file */ 787 /* Get path from configuration file */
762 if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string(cfg, "paths", "servicehome", &test_directory)) 788 if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string(cfg, "paths", "servicehome", &test_directory))
763 { 789 {
diff --git a/src/dht/test_dht_multipeer_data.conf b/src/dht/test_dht_multipeer_data.conf
index 17ebedbbd..c96560ccc 100644
--- a/src/dht/test_dht_multipeer_data.conf
+++ b/src/dht/test_dht_multipeer_data.conf
@@ -1,19 +1,27 @@
1[fs] 1[fs]
2AUTOSTART = NO 2AUTOSTART = NO
3 3
4[resolver]
5AUTOSTART = NO
6
4[dht] 7[dht]
5DEBUG = NO 8DEBUG = NO
6STOP_ON_CLOSEST = NO 9STOP_ON_CLOSEST = YES
7AUTOSTART = YES 10AUTOSTART = YES
8ACCEPT_FROM6 = ::1; 11ACCEPT_FROM6 = ::1;
9ACCEPT_FROM = 127.0.0.1; 12ACCEPT_FROM = 127.0.0.1;
10BINARY = gnunet-service-dht 13#BINARY = /home/mrwiggles/documents/research/gnunet/gnunet-ng/src/dht/.libs/gnunet-service-dht
11#PREFIX = xterm -T dht -e gdb --args 14#PREFIX = xterm -T dht -e gdb --args
12#PREFIX = valgrind --log-file=dht_%p 15#PREFIX = valgrind --log-file=dht_%p
13CONFIG = $DEFAULTCONFIG 16CONFIG = $DEFAULTCONFIG
14HOME = $SERVICEHOME 17HOME = $SERVICEHOME
15HOSTNAME = localhost 18HOSTNAME = localhost
16PORT = 2100 19PORT = 2100
20STOP_FOUND = YES
21USE_MAX_HOPS = YES
22MAX_HOPS = 16
23CONVERGE_BINARY = YES
24CONVERGE_MODIFIER = 4
17 25
18[block] 26[block]
19plugins = test dht 27plugins = test dht
@@ -65,9 +73,10 @@ TIMEOUT = 300000
65PORT = 12368 73PORT = 12368
66 74
67[DHT_TESTING] 75[DHT_TESTING]
68MYSQL_LOGGING_EXTENDED = YES 76MYSQL_LOGGING_EXTENDED = NO
69NUM_GETS = 10 77MYSQL_LOGGING = NO
70NUM_PUTS = 50 78NUM_GETS = 1
79NUM_PUTS = 1
71 80
72[TESTING] 81[TESTING]
73TOPOLOGY = CLIQUE 82TOPOLOGY = CLIQUE
@@ -77,7 +86,7 @@ CONNECT_TOPOLOGY = RING
77#LOGNMODIFIER = .65 86#LOGNMODIFIER = .65
78#PERCENTAGE = .75 87#PERCENTAGE = .75
79WEAKRANDOM = YES 88WEAKRANDOM = YES
80NUM_PEERS = 15 89NUM_PEERS = 5
81 90
82[gnunetd] 91[gnunetd]
83HOSTKEY = $SERVICEHOME/.hostkey 92HOSTKEY = $SERVICEHOME/.hostkey
diff --git a/src/dht/test_dht_twopeer.c b/src/dht/test_dht_twopeer.c
index d5923dc11..aab3a1231 100644
--- a/src/dht/test_dht_twopeer.c
+++ b/src/dht/test_dht_twopeer.c
@@ -220,7 +220,8 @@ get_stop_finished (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
220 &stop_retry_get, get_context); 220 &stop_retry_get, get_context);
221 get_context->get_handle = GNUNET_DHT_get_start(get_context->dht_handle, 221 get_context->get_handle = GNUNET_DHT_get_start(get_context->dht_handle,
222 GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5), 222 GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5),
223 0 /* FIXME: use real type */, &get_context->peer->hashPubKey, 223 GNUNET_BLOCK_TYPE_DHT_HELLO,
224 &get_context->peer->hashPubKey,
224 DEFAULT_GET_REPLICATION, 225 DEFAULT_GET_REPLICATION,
225 GNUNET_DHT_RO_NONE, 226 GNUNET_DHT_RO_NONE,
226 NULL, 0, 227 NULL, 0,
@@ -303,7 +304,6 @@ topology_callback (void *cls,
303 304
304 curr_get_ctx.dht_handle = peer1dht; 305 curr_get_ctx.dht_handle = peer1dht;
305 curr_get_ctx.peer = &peer2id; 306 curr_get_ctx.peer = &peer2id;
306 //GNUNET_SCHEDULER_add_now (&do_get, &curr_get_ctx);
307 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 2), &do_get, &curr_get_ctx); 307 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 2), &do_get, &curr_get_ctx);
308 } 308 }
309 else if (total_connections + failed_connections == expected_connections) 309 else if (total_connections + failed_connections == expected_connections)
diff --git a/src/dht/test_dht_twopeer_data.conf b/src/dht/test_dht_twopeer_data.conf
index 5110b3001..5df598d00 100644
--- a/src/dht/test_dht_twopeer_data.conf
+++ b/src/dht/test_dht_twopeer_data.conf
@@ -1,6 +1,9 @@
1[fs] 1[fs]
2AUTOSTART = NO 2AUTOSTART = NO
3 3
4[resolver]
5AUTOSTART = YES
6
4[dht] 7[dht]
5DEBUG = NO 8DEBUG = NO
6AUTOSTART = YES 9AUTOSTART = YES
diff --git a/src/dht/test_dht_twopeer_path_tracking.c b/src/dht/test_dht_twopeer_path_tracking.c
new file mode 100644
index 000000000..ab4bc81e0
--- /dev/null
+++ b/src/dht/test_dht_twopeer_path_tracking.c
@@ -0,0 +1,513 @@
1/*
2 This file is part of GNUnet.
3 (C) 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 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 * @file dht/test_dht_twopeer_path_tracking.c
22 * @brief testcase for testing DHT service with
23 * two running peers, logging the path of the dht requests.
24 */
25#include "platform.h"
26#include "gnunet_testing_lib.h"
27#include "gnunet_core_service.h"
28#include "gnunet_dht_service.h"
29
30/* DEFINES */
31#define VERBOSE GNUNET_NO
32
33/* Timeout for entire testcase */
34#define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
35
36/* Timeout for waiting for replies to get requests */
37#define GET_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30)
38
39/* If number of peers not in config file, use this number */
40#define DEFAULT_NUM_PEERS 2
41
42/* Globals */
43
44/**
45 * Directory to store temp data in, defined in config file
46 */
47static char *test_directory;
48
49/**
50 * Variable used to store the number of connections we should wait for.
51 */
52static unsigned int expected_connections;
53
54/**
55 * Variable used to keep track of how many peers aren't yet started.
56 */
57static unsigned long long peers_left;
58
59/**
60 * Handle to the set of all peers run for this test.
61 */
62static struct GNUNET_TESTING_PeerGroup *pg;
63
64/**
65 * Global handle we will use for GET requests.
66 */
67struct GNUNET_DHT_GetHandle *global_get_handle;
68
69
70/**
71 * Total number of peers to run, set based on config file.
72 */
73static unsigned long long num_peers;
74
75/**
76 * Global used to count how many connections we have currently
77 * been notified about (how many times has topology_callback been called
78 * with success?)
79 */
80static unsigned int total_connections;
81
82/**
83 * Global used to count how many failed connections we have
84 * been notified about (how many times has topology_callback
85 * been called with failure?)
86 */
87static unsigned int failed_connections;
88
89/* Task handle to use to schedule test failure */
90GNUNET_SCHEDULER_TaskIdentifier die_task;
91
92/* Global return value (0 for success, anything else for failure) */
93static int ok;
94
95/**
96 * Peer identity of the first peer started.
97 */
98static struct GNUNET_PeerIdentity peer1id;
99
100/**
101 * Peer identity of the second peer started.
102 */
103static struct GNUNET_PeerIdentity peer2id;
104
105/**
106 * Handle to the first peers DHT service (via the API)
107 */
108static struct GNUNET_DHT_Handle *peer1dht;
109
110/**
111 * Handle to the second peers DHT service (via the API)
112 */
113static struct GNUNET_DHT_Handle *peer2dht;
114
115/**
116 * Check whether peers successfully shut down.
117 */
118void shutdown_callback (void *cls,
119 const char *emsg)
120{
121 if (emsg != NULL)
122 {
123 if (ok == 0)
124 ok = 2;
125 }
126}
127
128/**
129 * Function scheduled to be run on the successful completion of this
130 * testcase. Specifically, called when our get request completes.
131 */
132static void
133finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
134{
135 GNUNET_assert (pg != NULL);
136 GNUNET_assert (peer1dht != NULL);
137 GNUNET_assert (peer2dht != NULL);
138 GNUNET_DHT_disconnect(peer1dht);
139 GNUNET_DHT_disconnect(peer2dht);
140 GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
141 ok = 0;
142}
143
144/**
145 * Continuation for the GNUNET_DHT_get_stop call, so that we don't shut
146 * down the peers without freeing memory associated with GET request.
147 */
148static void
149end_badly_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
150{
151 if (peer1dht != NULL)
152 GNUNET_DHT_disconnect(peer1dht);
153
154 if (peer2dht != NULL)
155 GNUNET_DHT_disconnect(peer2dht);
156
157 if (pg != NULL)
158 GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
159}
160
161/**
162 * Check if the get_handle is being used, if so stop the request. Either
163 * way, schedule the end_badly_cont function which actually shuts down the
164 * test.
165 */
166static void
167end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
168{
169 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failing test with error: `%s'!\n", (char *)cls);
170 if (global_get_handle != NULL)
171 {
172 GNUNET_DHT_get_stop(global_get_handle);
173 global_get_handle = NULL;
174 }
175 GNUNET_SCHEDULER_add_now(&end_badly_cont, NULL);
176 ok = 1;
177}
178
179/**
180 * Iterator called if the GET request initiated returns a response.
181 *
182 * @param cls closure
183 * @param exp when will this value expire
184 * @param key key of the result
185 * @param type type of the result
186 * @param size number of bytes in data
187 * @param data pointer to the result data
188 */
189void get_result_iterator (void *cls,
190 struct GNUNET_TIME_Absolute exp,
191 const GNUNET_HashCode * key,
192 const struct GNUNET_PeerIdentity * const *get_path,
193 const struct GNUNET_PeerIdentity * const *put_path,
194 enum GNUNET_BLOCK_Type type,
195 size_t size,
196 const void *data)
197{
198 GNUNET_HashCode original_key; /* Key data was stored data under */
199 char original_data[4]; /* Made up data that was stored */
200 memset(&original_key, 42, sizeof(GNUNET_HashCode)); /* Set the key to what it was set to previously */
201 memset(original_data, 43, sizeof(original_data));
202#if VERBOSE
203 unsigned int i;
204#endif
205
206 if ((0 != memcmp(&original_key, key, sizeof (GNUNET_HashCode))) || (0 != memcmp(original_data, data, sizeof(original_data))))
207 {
208 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Key or data is not the same as was inserted!\n");
209 GNUNET_SCHEDULER_cancel(die_task);
210 GNUNET_SCHEDULER_add_now(&end_badly, "key or data mismatch in get response!\n");
211 return;
212 }
213
214#if VERBOSE
215 if (put_path != NULL)
216 {
217 fprintf(stderr, "PUT Path: ");
218 for (i = 0; put_path[i] != NULL; i++)
219 fprintf(stderr, "%s%s", i == 0 ? "" : "->", GNUNET_i2s(put_path[i]));
220 fprintf(stderr, "\n");
221 }
222 if (get_path != NULL)
223 {
224 fprintf(stderr, "GET Path: ");
225 for (i = 0; get_path[i] != NULL; i++)
226 fprintf(stderr, "%s%s", i == 0 ? "" : "->", GNUNET_i2s(get_path[i]));
227 fprintf(stderr, "\n");
228 }
229#endif
230
231 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received correct GET response!\n");
232 GNUNET_SCHEDULER_cancel(die_task);
233 GNUNET_DHT_get_stop(global_get_handle);
234 GNUNET_SCHEDULER_add_now (&finish_testing, NULL);
235}
236
237/**
238 * Start the GET request for the same key/data that was inserted.
239 */
240static void
241do_get (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
242{
243 GNUNET_HashCode key; /* Key for data lookup */
244 memset(&key, 42, sizeof(GNUNET_HashCode)); /* Set the key to the same thing as when data was inserted */
245 global_get_handle = GNUNET_DHT_get_start(peer2dht, GNUNET_TIME_relative_get_forever(),
246 GNUNET_BLOCK_TYPE_TEST,
247 &key,
248 DEFAULT_GET_REPLICATION,
249 GNUNET_DHT_RO_RECORD_ROUTE,
250 NULL, 0,
251 NULL, 0,
252 &get_result_iterator, NULL);
253}
254
255/**
256 * Called when the PUT request has been transmitted to the DHT service.
257 * Schedule the GET request for some time in the future.
258 */
259static void
260put_finished (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
261{
262 GNUNET_SCHEDULER_cancel (die_task);
263 die_task = GNUNET_SCHEDULER_add_delayed (GET_TIMEOUT,
264 &end_badly, "waiting for get response (data not found)");
265 GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 10), &do_get, NULL);
266}
267
268/**
269 * Set up some data, and call API PUT function
270 */
271static void
272do_put (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
273{
274 GNUNET_HashCode key; /* Made up key to store data under */
275 char data[4]; /* Made up data to store */
276 memset(&key, 42, sizeof(GNUNET_HashCode)); /* Set the key to something simple so we can issue GET request */
277 memset(data, 43, sizeof(data));
278
279 /* Insert the data at the first peer */
280 GNUNET_DHT_put(peer1dht,
281 &key,
282 DEFAULT_PUT_REPLICATION,
283 GNUNET_DHT_RO_RECORD_ROUTE,
284 GNUNET_BLOCK_TYPE_TEST,
285 sizeof(data), data,
286 GNUNET_TIME_UNIT_FOREVER_ABS,
287 GNUNET_TIME_UNIT_FOREVER_REL,
288 &put_finished, NULL);
289}
290
291/**
292 * This function is called whenever a connection attempt is finished between two of
293 * the started peers (started with GNUNET_TESTING_daemons_start). The total
294 * number of times this function is called should equal the number returned
295 * from the GNUNET_TESTING_connect_topology call.
296 *
297 * The emsg variable is NULL on success (peers connected), and non-NULL on
298 * failure (peers failed to connect).
299 */
300void
301topology_callback (void *cls,
302 const struct GNUNET_PeerIdentity *first,
303 const struct GNUNET_PeerIdentity *second,
304 uint32_t distance,
305 const struct GNUNET_CONFIGURATION_Handle *first_cfg,
306 const struct GNUNET_CONFIGURATION_Handle *second_cfg,
307 struct GNUNET_TESTING_Daemon *first_daemon,
308 struct GNUNET_TESTING_Daemon *second_daemon,
309 const char *emsg)
310{
311 if (emsg == NULL)
312 {
313 total_connections++;
314#if VERBOSE
315 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s, distance %u\n",
316 first_daemon->shortname,
317 second_daemon->shortname,
318 distance);
319#endif
320 }
321#if VERBOSE
322 else
323 {
324 failed_connections++;
325 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect peer %s to peer %s with error :\n%s\n",
326 first_daemon->shortname,
327 second_daemon->shortname, emsg);
328 }
329#endif
330
331 if (total_connections == expected_connections)
332 {
333#if VERBOSE
334 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
335 "Created %d total connections, which is our target number! Starting next phase of testing.\n",
336 total_connections);
337#endif
338 GNUNET_SCHEDULER_cancel (die_task);
339 die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
340 &end_badly, "from test gets");
341
342 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 2), &do_put, NULL);
343 }
344 else if (total_connections + failed_connections == expected_connections)
345 {
346 GNUNET_SCHEDULER_cancel (die_task);
347 die_task = GNUNET_SCHEDULER_add_now (&end_badly, "from topology_callback (too many failed connections)");
348 }
349}
350
351
352/**
353 * Callback which is called whenever a peer is started (as a result of the
354 * GNUNET_TESTING_daemons_start call.
355 *
356 * @param cls closure argument given to GNUNET_TESTING_daemons_start
357 * @param id the GNUNET_PeerIdentity of the started peer
358 * @param cfg the configuration for this specific peer (needed to connect
359 * to the DHT)
360 * @param d the handle to the daemon started
361 * @param emsg NULL if peer started, non-NULL on error
362 */
363static void
364peers_started_callback (void *cls,
365 const struct GNUNET_PeerIdentity *id,
366 const struct GNUNET_CONFIGURATION_Handle *cfg,
367 struct GNUNET_TESTING_Daemon *d, const char *emsg)
368{
369 if (emsg != NULL)
370 {
371 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to start daemon with error: `%s'\n",
372 emsg);
373 return;
374 }
375 GNUNET_assert (id != NULL);
376
377 /* This is the first peer started */
378 if (peers_left == num_peers)
379 {
380 memcpy(&peer1id, id, sizeof(struct GNUNET_PeerIdentity)); /* Save the peer id */
381 peer1dht = GNUNET_DHT_connect(cfg, 100); /* Connect to the first peers DHT service */
382 if (peer1dht == NULL) /* If DHT connect failed */
383 {
384 GNUNET_SCHEDULER_cancel (die_task);
385 GNUNET_SCHEDULER_add_now(&end_badly, "Failed to get dht handle!\n");
386 }
387 }
388 else /* This is the second peer started */
389 {
390 memcpy(&peer2id, id, sizeof(struct GNUNET_PeerIdentity)); /* Same as for first peer... */
391 peer2dht = GNUNET_DHT_connect(cfg, 100);
392 if (peer2dht == NULL)
393 {
394 GNUNET_SCHEDULER_cancel (die_task);
395 GNUNET_SCHEDULER_add_now(&end_badly, "Failed to get dht handle!\n");
396 }
397 }
398
399 /* Decrement number of peers left to start */
400 peers_left--;
401
402 if (peers_left == 0) /* Indicates all peers started */
403 {
404#if VERBOSE
405 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
406 "All %d daemons started, now connecting peers!\n",
407 num_peers);
408#endif
409 expected_connections = -1;
410 if ((pg != NULL)) /* Sanity check */
411 {
412 /* Connect peers in a "straight line" topology, return the number of expected connections */
413 expected_connections = GNUNET_TESTING_connect_topology (pg, GNUNET_TESTING_TOPOLOGY_LINE, GNUNET_TESTING_TOPOLOGY_OPTION_ALL, 0.0, NULL, NULL);
414 }
415
416 /* Cancel current timeout fail task */
417 GNUNET_SCHEDULER_cancel (die_task);
418 if (expected_connections == GNUNET_SYSERR) /* Some error happened */
419 die_task = GNUNET_SCHEDULER_add_now (&end_badly, "from connect topology (bad return)");
420
421 /* Schedule timeout on failure task */
422 die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
423 &end_badly, "from connect topology (timeout)");
424 ok = 0;
425 }
426}
427
428static void
429run (void *cls,
430 char *const *args,
431 const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
432{
433
434 /* Get path from configuration file */
435 if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string(cfg, "paths", "servicehome", &test_directory))
436 {
437 ok = 404;
438 return;
439 }
440
441 /* Get number of peers to start from configuration (should be two) */
442 if (GNUNET_SYSERR ==
443 GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers",
444 &num_peers))
445 num_peers = DEFAULT_NUM_PEERS;
446
447 /* Set peers_left so we know when all peers started */
448 peers_left = num_peers;
449
450 /* Set up a task to end testing if peer start fails */
451 die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
452 &end_badly, "didn't start all daemons in reasonable amount of time!!!");
453
454 /* Start num_peers peers, call peers_started_callback on peer start, topology_callback on peer connect */
455 /* Read the API documentation for other parameters! */
456 pg = GNUNET_TESTING_daemons_start (cfg,
457 num_peers, TIMEOUT, NULL, NULL, &peers_started_callback, NULL,
458 &topology_callback, NULL, NULL);
459
460}
461
462static int
463check ()
464{
465 int ret;
466 /* Arguments for GNUNET_PROGRAM_run */
467 char *const argv[] = {"test-dht-twopeer-put-get", /* Name to give running binary */
468 "-c",
469 "test_dht_twopeer_data.conf", /* Config file to use */
470#if VERBOSE
471 "-L", "DEBUG",
472#endif
473 NULL
474 };
475 struct GNUNET_GETOPT_CommandLineOption options[] = {
476 GNUNET_GETOPT_OPTION_END
477 };
478 /* Run the run function as a new program */
479 ret = GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
480 argv, "test-dht-twopeer-put-get", "nohelp",
481 options, &run, &ok);
482 if (ret != GNUNET_OK)
483 {
484 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "`test-dht-twopeer': Failed with error code %d\n", ret);
485 }
486 return ok;
487}
488
489int
490main (int argc, char *argv[])
491{
492 int ret;
493
494 GNUNET_log_setup ("test-dht-twopeer",
495#if VERBOSE
496 "DEBUG",
497#else
498 "WARNING",
499#endif
500 NULL);
501 ret = check ();
502 /**
503 * Need to remove base directory, subdirectories taken care
504 * of by the testing framework.
505 */
506 if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK)
507 {
508 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Failed to remove testing directory %s\n", test_directory);
509 }
510 return ret;
511}
512
513/* end of test_dht_twopeer_put_get.c */
diff --git a/src/dht/test_dhtlog.c b/src/dht/test_dhtlog.c
index c8601b191..955781ef2 100644
--- a/src/dht/test_dhtlog.c
+++ b/src/dht/test_dhtlog.c
@@ -28,7 +28,7 @@
28#include "gnunet_protocols.h" 28#include "gnunet_protocols.h"
29#include "dhtlog.h" 29#include "dhtlog.h"
30 30
31#define VERBOSE GNUNET_YES 31#define VERBOSE GNUNET_NO
32 32
33static int ok; 33static int ok;
34 34
diff --git a/src/dht/test_dhtlog_data.conf b/src/dht/test_dhtlog_data.conf
index 22ef427aa..26244af0d 100644
--- a/src/dht/test_dhtlog_data.conf
+++ b/src/dht/test_dhtlog_data.conf
@@ -36,7 +36,7 @@ DEFAULTCONFIG = test_dhtlog_data.conf
36SERVICEHOME = /tmp/test-dhtlog/ 36SERVICEHOME = /tmp/test-dhtlog/
37 37
38[DHTLOG] 38[DHTLOG]
39#PLUGIN = mysql_dump 39#PLUGIN = mysql_dump_load
40PLUGIN = dummy 40PLUGIN = dummy
41#PLUGIN = mysql 41#PLUGIN = mysql
42 42