fix get error (never canceled) in test_dht_api, remove valgrind from conf
[oweals/gnunet.git] / src / dht / test_dht_api.c
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_api.c
22  * @brief base test case for dht api
23  *
24  * This test case tests DHT api to DUMMY DHT service communication.
25  *
26  */
27 #include "platform.h"
28 #include "gnunet_common.h"
29 #include "gnunet_hello_lib.h"
30 #include "gnunet_getopt_lib.h"
31 #include "gnunet_os_lib.h"
32 #include "gnunet_program_lib.h"
33 #include "gnunet_scheduler_lib.h"
34 #include "gnunet_dht_service.h"
35 #include "gnunet_hello_lib.h"
36
37 #define VERBOSE GNUNET_YES
38
39 #define VERBOSE_ARM GNUNET_NO
40
41 #define START_ARM GNUNET_YES
42
43 /**
44  * How long until we really give up on a particular testcase portion?
45  */
46 #define TOTAL_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 360)
47
48 /**
49  * How long until we give up on any particular operation (and retry)?
50  */
51 #define BASE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)
52
53 #define MTYPE 12345
54
55 struct RetryContext
56 {
57   /**
58    * When to really abort the operation.
59    */
60   struct GNUNET_TIME_Absolute real_timeout;
61
62   /**
63    * What timeout to set for the current attempt (increases)
64    */
65   struct GNUNET_TIME_Relative next_timeout;
66
67   /**
68    * The context of the peer we are dealing with.
69    */
70   struct PeerContext *peer_ctx;
71
72   /**
73    * The task identifier of the retry task, so it can be cancelled.
74    */
75   GNUNET_SCHEDULER_TaskIdentifier retry_task;
76
77 };
78
79 struct PeerContext
80 {
81   struct GNUNET_CONFIGURATION_Handle *cfg;
82   struct GNUNET_DHT_Handle *dht_handle;
83   struct GNUNET_PeerIdentity id;
84   struct GNUNET_DHT_GetHandle *get_handle;
85   struct GNUNET_DHT_FindPeerHandle *find_peer_handle;
86
87 #if START_ARM
88   pid_t arm_pid;
89 #endif
90 };
91
92 static struct PeerContext p1;
93
94 struct RetryContext retry_context;
95
96 static struct GNUNET_SCHEDULER_Handle *sched;
97
98 static int ok;
99
100 GNUNET_SCHEDULER_TaskIdentifier die_task;
101
102 #if VERBOSE
103 #define OKPP do { ok++; fprintf (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
104 #else
105 #define OKPP do { ok++; } while (0)
106 #endif
107
108
109 static void
110 end (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
111 {
112   GNUNET_SCHEDULER_cancel (sched, die_task);
113   die_task = GNUNET_SCHEDULER_NO_TASK;
114   GNUNET_DHT_disconnect (p1.dht_handle);
115   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
116               "DHT disconnected, returning success!\n");
117   ok = 0;
118 }
119
120 static void
121 stop_arm (struct PeerContext *p)
122 {
123 #if START_ARM
124   if (0 != PLIBC_KILL (p->arm_pid, SIGTERM))
125     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
126   GNUNET_OS_process_wait (p->arm_pid);
127 #endif
128   GNUNET_CONFIGURATION_destroy (p->cfg);
129 }
130
131
132 static void
133 end_badly ()
134 {
135   /* do work here */
136 #if VERBOSE
137   fprintf (stderr, "Ending on an unhappy note.\n");
138 #endif
139
140   if ( (retry_context.peer_ctx != NULL) && 
141        (retry_context.peer_ctx->find_peer_handle != NULL) )
142     {
143       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Stopping find peer request!\n");
144       GNUNET_DHT_find_peer_stop(retry_context.peer_ctx->find_peer_handle);
145     }
146   if ( (retry_context.peer_ctx != NULL) && 
147        (retry_context.peer_ctx->get_handle != NULL) )
148     {
149       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Stopping get request!\n");
150       GNUNET_DHT_get_stop (retry_context.peer_ctx->get_handle);
151     }
152   if (retry_context.retry_task != GNUNET_SCHEDULER_NO_TASK)
153     GNUNET_SCHEDULER_cancel(sched, retry_context.retry_task);
154   GNUNET_DHT_disconnect (p1.dht_handle);
155   ok = 1;
156 }
157
158
159 /**
160  * Signature of the main function of a task.
161  *
162  * @param cls closure
163  * @param tc context information (why was this task triggered now)
164  */
165 void
166 test_find_peer_stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
167 {
168   struct PeerContext *peer = cls;
169
170   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Called test_find_peer_stop!\n");
171   if (tc->reason == GNUNET_SCHEDULER_REASON_TIMEOUT)
172     {
173       GNUNET_break (0);
174       GNUNET_SCHEDULER_cancel (sched, die_task);
175       GNUNET_SCHEDULER_add_now (sched, &end_badly, NULL);
176       return;
177     }
178
179   GNUNET_assert (peer->dht_handle != NULL);
180
181   GNUNET_DHT_find_peer_stop (peer->find_peer_handle);
182
183 #if HAVE_MALICIOUS
184   GNUNET_DHT_set_malicious_getter (peer->dht_handle, GNUNET_TIME_UNIT_SECONDS);
185   GNUNET_DHT_set_malicious_putter (peer->dht_handle, GNUNET_TIME_UNIT_SECONDS);
186   GNUNET_DHT_set_malicious_dropper (peer->dht_handle);
187 #endif
188   GNUNET_SCHEDULER_add_delayed(sched, 
189                                GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 1), 
190                                &end, &p1);
191 }
192
193
194 /**
195  * Iterator called on each result obtained from a find peer
196  * operation
197  *
198  * @param cls closure (NULL)
199  * @param peer the peer we learned about
200  * @param reply response
201  */
202 void test_find_peer_processor (void *cls,
203                                const struct GNUNET_HELLO_Message *hello)
204 {
205   struct RetryContext *retry_ctx = cls;
206   struct GNUNET_PeerIdentity peer;
207
208   if (GNUNET_OK == GNUNET_HELLO_get_id(hello, &peer))
209     {
210       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
211                   "test_find_peer_processor called (peer `%s'), stopping find peer request!\n", GNUNET_i2s(&peer));
212
213       if (retry_ctx->retry_task != GNUNET_SCHEDULER_NO_TASK)
214         {
215           GNUNET_SCHEDULER_cancel(sched, retry_ctx->retry_task);
216           retry_ctx->retry_task = GNUNET_SCHEDULER_NO_TASK;
217         }
218
219       GNUNET_SCHEDULER_add_continuation (sched, &test_find_peer_stop, &p1,
220                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
221     }
222   else
223     {
224       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
225                   "received find peer request, but hello_get_id failed!\n");
226     }
227
228 }
229
230 /**
231  * Retry the find_peer task on timeout. (Forward declaration)
232  *
233  * @param cls closure
234  * @param tc context information (why was this task triggered now?)
235  */
236 void
237 retry_find_peer_stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
238
239 /**
240  * Retry the find_peer task on timeout.
241  *
242  * @param cls closure
243  * @param tc context information (why was this task triggered now)
244  */
245 void
246 retry_find_peer (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
247 {
248   struct RetryContext *retry_ctx = cls;
249   GNUNET_HashCode hash;
250   memset (&hash, 42, sizeof (GNUNET_HashCode));
251
252   if (GNUNET_TIME_absolute_get_remaining(retry_ctx->real_timeout).value > 0)
253     {
254       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
255                   "test_find_peer timed out, retrying!\n");
256       retry_ctx->next_timeout = GNUNET_TIME_relative_multiply(retry_ctx->next_timeout, 2);
257       retry_ctx->peer_ctx->find_peer_handle 
258         = GNUNET_DHT_find_peer_start (retry_ctx->peer_ctx->dht_handle, 
259                                       retry_ctx->next_timeout, &hash,
260                                       GNUNET_DHT_RO_NONE,
261                                       &test_find_peer_processor, retry_ctx);
262     }
263   else
264     {
265       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
266                   "test_find_peer timed out for good, failing!\n");
267
268       retry_ctx->peer_ctx->find_peer_handle = NULL;
269     }
270
271   if (retry_ctx->peer_ctx->find_peer_handle == NULL)
272     {
273       GNUNET_break (0);
274       GNUNET_SCHEDULER_cancel (sched, die_task);
275       GNUNET_SCHEDULER_add_now (sched, &end_badly, &p1);
276       return;
277     }
278   retry_ctx->retry_task = GNUNET_SCHEDULER_add_delayed(sched, retry_ctx->next_timeout, &retry_find_peer_stop, retry_ctx);
279 }
280
281 /**
282  * Retry the find_peer task on timeout.
283  *
284  * @param cls closure
285  * @param tc context information (why was this task triggered now?)
286  */
287 void
288 retry_find_peer_stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
289 {
290   struct RetryContext *retry_ctx = cls;
291   GNUNET_HashCode hash;
292   memset (&hash, 42, sizeof (GNUNET_HashCode));
293
294   if (retry_ctx->peer_ctx->find_peer_handle != NULL)
295     {
296       GNUNET_DHT_find_peer_stop(retry_ctx->peer_ctx->find_peer_handle);
297       retry_ctx->peer_ctx->find_peer_handle = NULL;
298     }  
299   GNUNET_SCHEDULER_add_now (sched, &retry_find_peer, retry_ctx);
300 }
301
302 /**
303  * Entry point for test of find_peer functionality.
304  *
305  * @param cls closure
306  * @param tc context information (why was this task triggered now)
307  */
308 void
309 test_find_peer (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
310 {
311   struct PeerContext *peer = cls;
312   GNUNET_HashCode hash;
313   memset (&hash, 42, sizeof (GNUNET_HashCode));
314
315   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Called test_find_peer!\n");
316   GNUNET_assert (peer->dht_handle != NULL);
317
318   retry_context.real_timeout = GNUNET_TIME_relative_to_absolute(TOTAL_TIMEOUT);
319   retry_context.next_timeout = BASE_TIMEOUT;
320   retry_context.peer_ctx = peer;
321
322   peer->find_peer_handle
323     = GNUNET_DHT_find_peer_start (peer->dht_handle, retry_context.next_timeout, 
324                                   &hash,
325                                   GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
326                                   &test_find_peer_processor, &retry_context);
327
328   if (peer->find_peer_handle == NULL)
329     {
330       GNUNET_break (0);
331       GNUNET_SCHEDULER_cancel (sched, die_task);
332       GNUNET_SCHEDULER_add_now (sched, &end_badly, &p1);
333       return;
334     }
335   retry_context.retry_task = GNUNET_SCHEDULER_add_delayed(sched, retry_context.next_timeout, &retry_find_peer_stop, &retry_context);
336 }
337
338 /**
339  * Signature of the main function of a task.
340  *
341  * @param cls closure
342  * @param tc context information (why was this task triggered now)
343  */
344 void
345 test_get_stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
346 {
347   struct PeerContext *peer = cls;
348
349   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Called test_get_stop!\n");
350   if (tc->reason == GNUNET_SCHEDULER_REASON_TIMEOUT)
351     {
352       GNUNET_break (0);
353       GNUNET_SCHEDULER_cancel (sched, die_task);
354       GNUNET_SCHEDULER_add_now (sched, &end_badly, NULL);
355       return;
356     }
357   GNUNET_assert (peer->dht_handle != NULL);
358   GNUNET_DHT_get_stop (peer->get_handle);
359   GNUNET_SCHEDULER_add_now(sched, 
360                            &test_find_peer, 
361                            &p1);
362 }
363
364 void
365 test_get_iterator (void *cls,
366                    struct GNUNET_TIME_Absolute exp,
367                    const GNUNET_HashCode * key,
368                    const struct GNUNET_PeerIdentity * const *get_path,
369                    const struct GNUNET_PeerIdentity * const *put_path,
370                    enum GNUNET_BLOCK_Type type, 
371                    size_t size, const void *data)
372 {
373   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
374               "test_get_iterator called (we got a result), stopping get request!\n");
375
376   GNUNET_SCHEDULER_add_continuation (sched, &test_get_stop, &p1,
377                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
378 }
379
380 /**
381  * Signature of the main function of a task.
382  *
383  * @param cls closure
384  * @param tc context information (why was this task triggered now)
385  */
386 void
387 test_get (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
388 {
389   struct PeerContext *peer = cls;
390   GNUNET_HashCode hash;
391   memset (&hash, 42, sizeof (GNUNET_HashCode));
392
393   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Called test_get!\n");
394
395   GNUNET_assert (peer->dht_handle != NULL);
396   retry_context.real_timeout = GNUNET_TIME_relative_to_absolute(TOTAL_TIMEOUT);
397   retry_context.next_timeout = BASE_TIMEOUT;
398
399   peer->get_handle =
400     GNUNET_DHT_get_start (peer->dht_handle, 
401                           TOTAL_TIMEOUT,
402                           GNUNET_BLOCK_TYPE_TEST,
403                           &hash,
404                           GNUNET_DHT_RO_NONE,
405                           NULL, 0,
406                           NULL, 0,
407                           &test_get_iterator, NULL);
408
409   if (peer->get_handle == NULL)
410     {
411       GNUNET_break (0);
412       GNUNET_SCHEDULER_cancel (sched, die_task);
413       GNUNET_SCHEDULER_add_now (sched, &end_badly, &p1);
414       return;
415     }
416
417   retry_context.peer_ctx = peer;
418 }
419
420 /**
421  * Signature of the main function of a task.
422  *
423  * @param cls closure
424  * @param tc context information (why was this task triggered now)
425  */
426 void
427 test_put (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
428 {
429   struct PeerContext *peer = cls;
430   GNUNET_HashCode hash;
431   char *data;
432   size_t data_size = 42;
433   memset (&hash, 42, sizeof (GNUNET_HashCode));
434   data = GNUNET_malloc (data_size);
435   memset (data, 43, data_size);
436   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Called test_put!\n");
437   peer->dht_handle = GNUNET_DHT_connect (sched, peer->cfg, 100);
438
439   GNUNET_assert (peer->dht_handle != NULL);
440
441   GNUNET_DHT_put (peer->dht_handle, &hash, 
442                   GNUNET_DHT_RO_NONE,
443                   GNUNET_BLOCK_TYPE_TEST,
444                   data_size, data,
445                   GNUNET_TIME_relative_to_absolute (TOTAL_TIMEOUT),
446                   TOTAL_TIMEOUT,
447                   &test_get, &p1);
448   GNUNET_free(data);
449 }
450
451 static void
452 setup_peer (struct PeerContext *p, const char *cfgname)
453 {
454   p->cfg = GNUNET_CONFIGURATION_create ();
455 #if START_ARM
456   p->arm_pid = GNUNET_OS_start_process (NULL, NULL, "gnunet-service-arm",
457                                         "gnunet-service-arm",
458 #if VERBOSE_ARM
459                                         "-L", "DEBUG",
460 #endif
461                                         "-c", cfgname, NULL);
462 #endif
463   GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
464
465 }
466
467 static void
468 run (void *cls,
469      struct GNUNET_SCHEDULER_Handle *s,
470      char *const *args,
471      const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
472 {
473   GNUNET_assert (ok == 1);
474   OKPP;
475   sched = s;
476
477   die_task = GNUNET_SCHEDULER_add_delayed (sched,
478                                            GNUNET_TIME_relative_multiply
479                                            (GNUNET_TIME_UNIT_MINUTES, 1),
480                                            &end_badly, NULL);
481
482   setup_peer (&p1, "test_dht_api_peer1.conf");
483
484   GNUNET_SCHEDULER_add_delayed (sched,
485                                 GNUNET_TIME_relative_multiply
486                                 (GNUNET_TIME_UNIT_SECONDS, 1), &test_put,
487                                 &p1);
488 }
489
490 static int
491 check ()
492 {
493
494   char *const argv[] = { "test-dht-api",
495     "-c",
496     "test_dht_api_data.conf",
497 #if VERBOSE
498     "-L", "DEBUG",
499 #endif
500     NULL
501   };
502
503   struct GNUNET_GETOPT_CommandLineOption options[] = {
504     GNUNET_GETOPT_OPTION_END
505   };
506
507   ok = 1;
508   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
509                       argv, "test-dht-api", "nohelp", options, &run, &ok);
510   stop_arm (&p1);
511   return ok;
512 }
513
514
515 int
516 main (int argc, char *argv[])
517 {
518   int ret;
519 #ifdef MINGW
520   return GNUNET_SYSERR;
521 #endif
522
523   GNUNET_log_setup ("test-dht-api",
524 #if VERBOSE
525                     "DEBUG",
526 #else
527                     "WARNING",
528 #endif
529                     NULL);
530   ret = check ();
531
532   GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-dht-peer-1");
533
534   return ret;
535 }
536
537 /* end of test_dht_api.c */