more testcases, allow location uris in fs_download
[oweals/gnunet.git] / src / fs / fs_test_lib.c
1 /*
2      This file is part of GNUnet.
3      (C) 2010 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 fs/fs_test_lib.c
23  * @brief library routines for testing FS publishing and downloading
24  *        with multiple peers; this code is limited to flat files
25  *        and no keywords (those functions can be tested with
26  *        single-peer setups; this is for testing routing).
27  * @author Christian Grothoff
28  */
29 #include "platform.h"
30 #include "fs.h"
31 #include "fs_test_lib.h"
32 #include "gnunet_testing_lib.h"
33
34 #define CONNECT_ATTEMPTS 4
35
36 /**
37  * Handle for a daemon started for testing FS.
38  */
39 struct GNUNET_FS_TestDaemon
40 {
41
42   /**
43    * Global configuration, only stored in first test daemon,
44    * otherwise NULL.
45    */
46   struct GNUNET_CONFIGURATION_Handle *gcfg;
47
48   /**
49    * Handle to the file sharing context using this daemon.
50    */
51   struct GNUNET_FS_Handle *fs;
52
53   /**
54    * Handle to the daemon via testing.
55    */
56   struct GNUNET_TESTING_Daemon *daemon;
57
58   /**
59    * Note that 'group' will be the same value for all of the
60    * daemons started jointly.
61    */
62   struct GNUNET_TESTING_PeerGroup *group;
63
64   /**
65    * Configuration for accessing this peer.
66    */
67   struct GNUNET_CONFIGURATION_Handle *cfg;
68
69   /**
70    * ID of this peer.
71    */
72   struct GNUNET_PeerIdentity id;
73
74   /**
75    * Scheduler to use (for publish_cont).
76    */
77   struct GNUNET_SCHEDULER_Handle *publish_sched;
78
79   /**
80    * Function to call when upload is done.
81    */
82   GNUNET_FS_TEST_UriContinuation publish_cont;
83   
84   /**
85    * Closure for publish_cont.
86    */
87   void *publish_cont_cls;
88
89   /**
90    * Task to abort publishing (timeout).
91    */
92   GNUNET_SCHEDULER_TaskIdentifier publish_timeout_task;
93
94   /**
95    * Seed for file generation.
96    */
97   uint32_t publish_seed;
98
99   /**
100    * Context for current publishing operation.
101    */
102   struct GNUNET_FS_PublishContext *publish_context;
103
104   /**
105    * Result URI.
106    */
107   struct GNUNET_FS_Uri *publish_uri;
108
109   /**
110    * Name of the temporary file used, or NULL for none.
111    */ 
112   char *publish_tmp_file;
113
114   /**
115    * Scheduler to use (for download_cont).
116    */
117   struct GNUNET_SCHEDULER_Handle *download_sched;
118
119   /**
120    * Function to call when download is done.
121    */
122   GNUNET_SCHEDULER_Task download_cont;
123
124   /**
125    * Closure for download_cont.
126    */
127   void *download_cont_cls;
128
129   /**
130    * Seed for download verification.
131    */
132   uint32_t download_seed;
133
134   /**
135    * Task to abort downloading (timeout).
136    */
137   GNUNET_SCHEDULER_TaskIdentifier download_timeout_task;
138
139   /**
140    * Context for current download operation.
141    */  
142   struct GNUNET_FS_DownloadContext *download_context;
143
144   /**
145    * Verbosity level of the current operation.
146    */
147   int verbose;
148
149                 
150 };
151
152 /**
153  * Check whether peers successfully shut down.
154  */
155 static void 
156 shutdown_callback (void *cls,
157                    const char *emsg)
158 {
159   struct GNUNET_CONFIGURATION_Handle *gcfg = cls;
160
161   if (emsg != NULL)
162     {
163       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
164                   "Shutdown of peers failed: %s\n",
165                   emsg);
166     }
167   else
168     {
169 #if VERBOSE
170       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
171                   "All peers successfully shut down!\n");
172 #endif
173     }
174   if (gcfg != NULL)
175     GNUNET_CONFIGURATION_destroy (gcfg);
176 }
177
178
179 static void
180 report_uri (void *cls,
181             const struct GNUNET_SCHEDULER_TaskContext *tc)
182 {
183   struct GNUNET_FS_TestDaemon *daemon = cls;
184   GNUNET_FS_TEST_UriContinuation cont;
185   struct GNUNET_FS_Uri *uri;
186
187   GNUNET_FS_publish_stop (daemon->publish_context);
188   daemon->publish_context = NULL;
189   daemon->publish_sched = NULL;
190   cont = daemon->publish_cont;
191   daemon->publish_cont = NULL;
192   uri = daemon->publish_uri;
193   cont (daemon->publish_cont_cls,
194         uri);
195   GNUNET_FS_uri_destroy (uri);
196 }            
197
198
199 static void
200 report_success (void *cls,
201                 const struct GNUNET_SCHEDULER_TaskContext *tc)
202 {
203   struct GNUNET_FS_TestDaemon *daemon = cls;
204
205   GNUNET_FS_download_stop (daemon->download_context, GNUNET_YES);
206   daemon->download_context = NULL;
207   GNUNET_SCHEDULER_add_continuation (daemon->download_sched,
208                                      daemon->download_cont,
209                                      daemon->download_cont_cls,
210                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);      
211   daemon->download_cont = NULL;
212   daemon->download_sched = NULL;
213 }
214
215
216 static void*
217 progress_cb (void *cls,
218              const struct GNUNET_FS_ProgressInfo *info)
219 {
220   struct GNUNET_FS_TestDaemon *daemon = cls;
221
222   switch (info->status)
223     {
224     case GNUNET_FS_STATUS_PUBLISH_COMPLETED:      
225       GNUNET_SCHEDULER_cancel (daemon->publish_sched,
226                                daemon->publish_timeout_task);
227       daemon->publish_timeout_task = GNUNET_SCHEDULER_NO_TASK;
228       daemon->publish_uri = GNUNET_FS_uri_dup (info->value.publish.specifics.completed.chk_uri);
229       GNUNET_SCHEDULER_add_continuation (daemon->publish_sched,
230                                          &report_uri,
231                                          daemon,
232                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
233       break;
234     case GNUNET_FS_STATUS_PUBLISH_PROGRESS:
235       if (daemon->verbose)
236         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
237                     "Publishing at %llu/%llu bytes\n",
238                     (unsigned long long) info->value.publish.completed,
239                     (unsigned long long) info->value.publish.size);
240       break;
241     case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS:
242       if (daemon->verbose)
243         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
244                     "Download at %llu/%llu bytes\n",
245                     (unsigned long long) info->value.download.completed,
246                     (unsigned long long) info->value.download.size);
247       break;
248     case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED:
249       GNUNET_SCHEDULER_cancel (daemon->download_sched,
250                                daemon->download_timeout_task);
251       daemon->download_timeout_task = GNUNET_SCHEDULER_NO_TASK;
252       GNUNET_SCHEDULER_add_continuation (daemon->download_sched,
253                                          &report_success,
254                                          daemon,
255                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
256       break;
257     case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE:
258     case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE:
259       break;
260       /* FIXME: monitor data correctness during download progress */
261       /* FIXME: do performance reports given sufficient verbosity */
262       /* FIXME: advance timeout task to "immediate" on error */
263     default:
264       break;
265     }
266   return NULL;
267 }
268
269
270 struct StartContext
271 {
272   struct GNUNET_SCHEDULER_Handle *sched;
273   struct GNUNET_TIME_Relative timeout;
274   unsigned int total;
275   unsigned int have;
276   struct GNUNET_FS_TestDaemon **daemons;
277   GNUNET_SCHEDULER_Task cont;
278   void *cont_cls;
279   struct GNUNET_TESTING_PeerGroup *group;
280   struct GNUNET_CONFIGURATION_Handle *cfg;
281   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
282 };
283
284
285 static void 
286 notify_running (void *cls,
287                 const struct GNUNET_PeerIdentity *id,
288                 const struct GNUNET_CONFIGURATION_Handle *cfg,
289                 struct GNUNET_TESTING_Daemon *d,
290                 const char *emsg)
291 {
292   struct StartContext *sctx = cls;
293   unsigned int i;
294
295   if (emsg != NULL)
296     {
297       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
298                   _("Failed to start daemon: %s\n"),
299                   emsg);
300       return;
301     }
302   i = 0;
303   while (i < sctx->total)
304     {
305       if (GNUNET_TESTING_daemon_get (sctx->group,
306                                      i) == d)
307         break;
308       i++;
309     }
310   GNUNET_assert (i < sctx->total);
311   GNUNET_assert (sctx->have < sctx->total);
312   GNUNET_assert (sctx->daemons[i]->cfg == NULL);
313   sctx->daemons[i]->cfg = GNUNET_CONFIGURATION_dup (cfg);
314   sctx->daemons[i]->group = sctx->group;
315   sctx->daemons[i]->daemon = d;
316   sctx->daemons[i]->id = *id;
317   sctx->have++;
318   if (sctx->have == sctx->total)
319     {
320       GNUNET_SCHEDULER_add_continuation (sctx->sched,
321                                          sctx->cont,
322                                          sctx->cont_cls,
323                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
324       sctx->daemons[0]->gcfg = sctx->cfg;
325       GNUNET_SCHEDULER_cancel (sctx->sched,
326                                sctx->timeout_task);
327       for (i=0;i<sctx->total;i++)
328         {
329           sctx->daemons[i]->fs = GNUNET_FS_start (sctx->sched,
330                                                   sctx->daemons[i]->cfg,
331                                                   "<tester>",
332                                                   &progress_cb,
333                                                   sctx->daemons[i],
334                                                   GNUNET_FS_FLAGS_NONE,
335                                                   GNUNET_FS_OPTIONS_END);
336         }
337       GNUNET_free (sctx);
338     }
339 }
340
341
342 static void
343 start_timeout (void *cls,
344                const struct GNUNET_SCHEDULER_TaskContext *tc)
345 {
346   struct StartContext *sctx = cls;
347   unsigned int i;
348
349   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
350               "Timeout while trying to start daemons\n");
351   GNUNET_TESTING_daemons_stop (sctx->group,
352                                GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30), 
353                                &shutdown_callback,
354                                NULL);
355   for (i=0;i<sctx->total;i++)
356     {
357       if (i < sctx->have)
358         GNUNET_CONFIGURATION_destroy (sctx->daemons[i]->cfg);
359       GNUNET_free (sctx->daemons[i]);
360       sctx->daemons[i] = NULL;
361     }
362   GNUNET_CONFIGURATION_destroy (sctx->cfg);
363   GNUNET_SCHEDULER_add_continuation (sctx->sched,
364                                      sctx->cont,
365                                      sctx->cont_cls,
366                                      GNUNET_SCHEDULER_REASON_TIMEOUT);
367   GNUNET_free (sctx);
368 }
369
370
371 /**
372  * Start daemons for testing.
373  *
374  * @param sched scheduler to use
375  * @param template_cfg_file configuration template to use
376  * @param timeout if this operation cannot be completed within the
377  *                given period, call the continuation with an error code
378  * @param total number of daemons to start
379  * @param daemons array of 'total' entries to be initialized
380  *                (array must already be allocated, will be filled)
381  * @param cont function to call when done
382  * @param cont_cls closure for cont
383  */
384 void
385 GNUNET_FS_TEST_daemons_start (struct GNUNET_SCHEDULER_Handle *sched,
386                               const char *template_cfg_file,
387                               struct GNUNET_TIME_Relative timeout,
388                               unsigned int total,
389                               struct GNUNET_FS_TestDaemon **daemons,
390                               GNUNET_SCHEDULER_Task cont,
391                               void *cont_cls)
392 {
393   struct StartContext *sctx;
394   unsigned int i;
395
396   GNUNET_assert (total > 0);
397   sctx = GNUNET_malloc (sizeof (struct StartContext));
398   sctx->sched = sched;
399   sctx->daemons = daemons;
400   sctx->total = total;
401   sctx->cont = cont;
402   sctx->cont_cls = cont_cls;
403   sctx->cfg = GNUNET_CONFIGURATION_create ();
404   if (GNUNET_OK !=
405       GNUNET_CONFIGURATION_load (sctx->cfg,
406                                  template_cfg_file))
407     {
408       GNUNET_break (0);
409       GNUNET_CONFIGURATION_destroy (sctx->cfg);
410       GNUNET_free (sctx);
411       GNUNET_SCHEDULER_add_continuation (sched,
412                                          cont,
413                                          cont_cls,
414                                          GNUNET_SCHEDULER_REASON_TIMEOUT);
415       return;
416     }
417   for (i=0;i<total;i++)
418     daemons[i] = GNUNET_malloc (sizeof (struct GNUNET_FS_TestDaemon));
419   sctx->group = GNUNET_TESTING_daemons_start (sched,
420                                               sctx->cfg,
421                                               total,
422                                               timeout,
423                                               NULL,
424                                               NULL,
425                                               &notify_running,
426                                               sctx,
427                                               NULL, NULL,
428                                               NULL);
429   sctx->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
430                                                      timeout,
431                                                      &start_timeout,
432                                                      sctx);
433 }
434
435
436 struct ConnectContext
437 {
438   struct GNUNET_SCHEDULER_Handle *sched;
439   GNUNET_SCHEDULER_Task cont;
440   void *cont_cls;
441 };
442
443
444 /**
445  * Prototype of a function that will be called whenever
446  * two daemons are connected by the testing library.
447  *
448  * @param cls closure
449  * @param first peer id for first daemon
450  * @param second peer id for the second daemon
451  * @param distance distance between the connected peers
452  * @param first_cfg config for the first daemon
453  * @param second_cfg config for the second daemon
454  * @param first_daemon handle for the first daemon
455  * @param second_daemon handle for the second daemon
456  * @param emsg error message (NULL on success)
457  */
458 static void
459 notify_connection (void *cls,
460                    const struct GNUNET_PeerIdentity *first,
461                    const struct GNUNET_PeerIdentity *second,
462                    uint32_t distance,
463                    const struct GNUNET_CONFIGURATION_Handle *first_cfg,
464                    const struct GNUNET_CONFIGURATION_Handle *second_cfg,
465                    struct GNUNET_TESTING_Daemon *first_daemon,
466                    struct GNUNET_TESTING_Daemon *second_daemon,
467                    const char *emsg)
468 {
469   struct ConnectContext *cc = cls;
470   
471   if (emsg != NULL)
472     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
473                 "Failed to connect peers: %s\n",
474                 emsg);
475   GNUNET_SCHEDULER_add_continuation (cc->sched,
476                                      cc->cont,
477                                      cc->cont_cls,
478                                      (emsg != NULL) 
479                                      ? GNUNET_SCHEDULER_REASON_TIMEOUT 
480                                      : GNUNET_SCHEDULER_REASON_PREREQ_DONE);
481   GNUNET_free (cc);
482 }
483
484
485 /**
486  * Connect two daemons for testing.
487  *
488  * @param sched scheduler to use
489  * @param daemon1 first daemon to connect
490  * @param daemon2 second first daemon to connect
491  * @param timeout if this operation cannot be completed within the
492  *                given period, call the continuation with an error code
493  * @param cont function to call when done
494  * @param cont_cls closure for cont
495  */
496 void
497 GNUNET_FS_TEST_daemons_connect (struct GNUNET_SCHEDULER_Handle *sched,
498                                 struct GNUNET_FS_TestDaemon *daemon1,
499                                 struct GNUNET_FS_TestDaemon *daemon2,
500                                 struct GNUNET_TIME_Relative timeout,
501                                 GNUNET_SCHEDULER_Task cont,
502                                 void *cont_cls)
503 {
504   struct ConnectContext *ncc;
505
506   ncc = GNUNET_malloc (sizeof (struct ConnectContext));
507   ncc->sched = sched;
508   ncc->cont = cont;
509   ncc->cont_cls = cont_cls;
510   GNUNET_TESTING_daemons_connect (daemon1->daemon,
511                                   daemon2->daemon,
512                                   timeout,
513                                   CONNECT_ATTEMPTS,
514                                   &notify_connection,
515                                   ncc);
516 }
517
518
519 /**
520  * Obtain peer configuration used for testing.
521  *
522  * @param daemons array with the daemons
523  * @param off which configuration to get
524  * @return peer configuration
525  */
526 const struct GNUNET_CONFIGURATION_Handle *
527 GNUNET_FS_TEST_get_configuration (struct GNUNET_FS_TestDaemon **daemons,
528                                   unsigned int off)
529 {
530   return daemons[off]->cfg;  
531 }
532
533 /**
534  * Obtain peer group used for testing.
535  *
536  * @param daemons array with the daemons (must contain at least one)
537  * @return peer group
538  */
539 struct GNUNET_TESTING_PeerGroup *
540 GNUNET_FS_TEST_get_group (struct GNUNET_FS_TestDaemon **daemons)
541 {
542   return daemons[0]->group;  
543 }
544
545
546 /**
547  * Stop daemons used for testing.
548  *
549  * @param sched scheduler to use
550  * @param total number of daemons to stop
551  * @param daemons array with the daemons (values will be clobbered)
552  */
553 void
554 GNUNET_FS_TEST_daemons_stop (struct GNUNET_SCHEDULER_Handle *sched,
555                              unsigned int total,
556                              struct GNUNET_FS_TestDaemon **daemons)
557 {
558   unsigned int i;
559   struct GNUNET_TESTING_PeerGroup *pg;
560   struct GNUNET_CONFIGURATION_Handle *gcfg;
561
562   GNUNET_assert (total > 0);
563   pg = daemons[0]->group;
564   gcfg = daemons[0]->gcfg;
565   for (i=0;i<total;i++)
566     {
567       if (daemons[i]->fs != NULL)
568         GNUNET_FS_stop (daemons[i]->fs);
569       if (daemons[i]->cfg != NULL)
570         GNUNET_CONFIGURATION_destroy (daemons[i]->cfg);
571       if (NULL != daemons[i]->publish_tmp_file)
572         {
573           GNUNET_DISK_directory_remove (daemons[i]->publish_tmp_file);
574           GNUNET_free (daemons[i]->publish_tmp_file);
575         }
576       GNUNET_free (daemons[i]);
577       daemons[i] = NULL;
578     }  
579   GNUNET_TESTING_daemons_stop (pg, 
580                                GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30), 
581                                &shutdown_callback, 
582                                gcfg);
583 }
584
585
586 static void
587 publish_timeout (void *cls,
588                  const struct GNUNET_SCHEDULER_TaskContext *tc)
589 {
590   struct GNUNET_FS_TestDaemon *daemon = cls;
591   GNUNET_FS_TEST_UriContinuation cont;
592
593   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
594               "Timeout while trying to publish data\n");
595   cont = daemon->publish_cont;
596   daemon->publish_timeout_task = GNUNET_SCHEDULER_NO_TASK;
597   daemon->publish_cont = NULL;
598   GNUNET_FS_publish_stop (daemon->publish_context);
599   daemon->publish_context = NULL;
600   cont (daemon->publish_cont_cls,
601         NULL);
602 }
603
604
605 static size_t
606 file_generator (void *cls, 
607                 uint64_t offset,
608                 size_t max, 
609                 void *buf,
610                 char **emsg)
611 {
612   struct GNUNET_FS_TestDaemon *daemon = cls;
613   uint64_t pos;
614   uint8_t *cbuf = buf;
615   int mod;
616
617   if (buf == NULL)
618     return 0;
619   for (pos=0;pos<8;pos++)
620     cbuf[pos] = (uint8_t) (offset >> pos*8);
621   for (pos=8;pos<max;pos++)
622     {
623       mod = (255 - (offset / 1024 / 32));
624       if (mod == 0)
625         mod = 1;
626       cbuf[pos] = (uint8_t) ((offset * daemon->publish_seed) % mod);  
627     }
628   return max;
629 }
630
631
632
633 /**
634  * Publish a file at the given daemon.
635  *
636  * @param sched scheduler to use
637  * @param daemon where to publish
638  * @param timeout if this operation cannot be completed within the
639  *                given period, call the continuation with an error code
640  * @param anonymity option for publication
641  * @param do_index GNUNET_YES for index, GNUNET_NO for insertion,
642  *                GNUNET_SYSERR for simulation
643  * @param size size of the file to publish
644  * @param seed seed to use for file generation
645  * @param verbose how verbose to be in reporting
646  * @param cont function to call when done
647  * @param cont_cls closure for cont
648  */
649 void
650 GNUNET_FS_TEST_publish (struct GNUNET_SCHEDULER_Handle *sched,
651                         struct GNUNET_FS_TestDaemon *daemon,
652                         struct GNUNET_TIME_Relative timeout,
653                         uint32_t anonymity,
654                         int do_index,
655                         uint64_t size,
656                         uint32_t seed,
657                         unsigned int verbose,
658                         GNUNET_FS_TEST_UriContinuation cont,
659                         void *cont_cls)
660 {
661   struct GNUNET_FS_FileInformation *fi;
662   struct GNUNET_DISK_FileHandle *fh;
663   char *emsg;
664   uint64_t off;
665   char buf[DBLOCK_SIZE];
666   size_t bsize;
667
668   GNUNET_assert (daemon->publish_cont == NULL);
669   daemon->publish_cont = cont;
670   daemon->publish_cont_cls = cont_cls;
671   daemon->publish_seed = seed;
672   daemon->verbose = verbose;
673   daemon->publish_sched = sched;
674   if (GNUNET_YES == do_index)
675     {
676       GNUNET_assert (daemon->publish_tmp_file == NULL);
677       daemon->publish_tmp_file = GNUNET_DISK_mktemp ("fs-test-publish-index");
678       GNUNET_assert (daemon->publish_tmp_file != NULL);
679       fh = GNUNET_DISK_file_open (daemon->publish_tmp_file,
680                                   GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE,
681                                   GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
682       GNUNET_assert (NULL != fh);
683       off = 0;      
684       while (off < size)
685         {
686           bsize = GNUNET_MIN (sizeof (buf),
687                               size - off);
688           GNUNET_assert (bsize ==
689                          file_generator (daemon,
690                                          off,
691                                          bsize,
692                                          buf,
693                                          &emsg));
694           GNUNET_assert (emsg == NULL);
695           GNUNET_assert (bsize ==
696                          GNUNET_DISK_file_write (fh,
697                                                  buf,
698                                                  bsize));
699           off += bsize;
700         }
701       GNUNET_assert (GNUNET_OK ==
702                      GNUNET_DISK_file_close (fh));
703       fi = GNUNET_FS_file_information_create_from_file (daemon->fs,
704                                                         daemon,                                               
705                                                         daemon->publish_tmp_file,
706                                                         NULL, NULL,
707                                                         do_index,
708                                                         anonymity,
709                                                         42 /* priority */,
710                                                         GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS));
711     }
712   else
713     {
714       fi = GNUNET_FS_file_information_create_from_reader (daemon->fs,
715                                                           daemon,                                                     
716                                                           size,
717                                                           &file_generator,
718                                                           daemon,
719                                                           NULL,
720                                                           NULL,
721                                                           do_index,
722                                                           anonymity,
723                                                           42 /* priority */,
724                                                           GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS));
725     }
726   daemon->publish_context = GNUNET_FS_publish_start (daemon->fs,
727                                                      fi,
728                                                      NULL, NULL, NULL,
729                                                      GNUNET_FS_PUBLISH_OPTION_NONE);
730   daemon->publish_timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
731                                                                timeout,
732                                                                &publish_timeout,
733                                                                daemon);
734 }
735
736
737 static void
738 download_timeout (void *cls,
739                   const struct GNUNET_SCHEDULER_TaskContext *tc)
740 {
741   struct GNUNET_FS_TestDaemon *daemon = cls;
742
743   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
744               "Timeout while trying to download file\n");
745   daemon->download_timeout_task = GNUNET_SCHEDULER_NO_TASK;
746   GNUNET_FS_download_stop (daemon->download_context, GNUNET_YES);
747   daemon->download_context = NULL;
748   GNUNET_SCHEDULER_add_continuation (daemon->download_sched,
749                                      daemon->download_cont,
750                                      daemon->download_cont_cls,
751                                      GNUNET_SCHEDULER_REASON_TIMEOUT);
752   daemon->download_cont = NULL;
753   daemon->download_sched = NULL;
754 }
755
756
757 /**
758  * Perform test download.
759  *
760  * @param sched scheduler to use
761  * @param daemon which peer to download from
762  * @param timeout if this operation cannot be completed within the
763  *                given period, call the continuation with an error code
764  * @param anonymity option for download
765  * @param seed used for file validation
766  * @param uri URI of file to download (CHK/LOC only)
767  * @param verbose how verbose to be in reporting
768  * @param cont function to call when done
769  * @param cont_cls closure for cont
770  */
771 void
772 GNUNET_FS_TEST_download (struct GNUNET_SCHEDULER_Handle *sched,
773                          struct GNUNET_FS_TestDaemon *daemon,
774                          struct GNUNET_TIME_Relative timeout,
775                          uint32_t anonymity,
776                          uint32_t seed,
777                          const struct GNUNET_FS_Uri *uri,
778                          unsigned int verbose,
779                          GNUNET_SCHEDULER_Task cont,
780                          void *cont_cls)
781 {
782   uint64_t size;
783  
784   GNUNET_assert (daemon->download_cont == NULL);
785   size = GNUNET_FS_uri_chk_get_file_size (uri);
786   daemon->verbose = verbose;
787   daemon->download_sched = sched;
788   daemon->download_cont = cont;
789   daemon->download_cont_cls = cont_cls;
790   daemon->download_seed = seed;  
791   daemon->download_context = GNUNET_FS_download_start (daemon->fs,
792                                                        uri,
793                                                        NULL, NULL,
794                                                        NULL,
795                                                        0,
796                                                        size,
797                                                        anonymity,
798                                                        GNUNET_FS_DOWNLOAD_OPTION_NONE,
799                                                        NULL,
800                                                        NULL);
801   daemon->download_timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
802                                                                 timeout,
803                                                                 &download_timeout,
804                                                                 daemon);
805 }
806
807 /* end of test_fs_lib.c */