aboutsummaryrefslogtreecommitdiff
path: root/src/fs/fs_download.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fs/fs_download.c')
-rw-r--r--src/fs/fs_download.c333
1 files changed, 282 insertions, 51 deletions
diff --git a/src/fs/fs_download.c b/src/fs/fs_download.c
index ebe9b5cac..6943f10b5 100644
--- a/src/fs/fs_download.c
+++ b/src/fs/fs_download.c
@@ -24,7 +24,6 @@
24 * 24 *
25 * TODO: 25 * TODO:
26 * - different priority for scheduling probe downloads? 26 * - different priority for scheduling probe downloads?
27 * - check if iblocks can be computed from existing blocks (can wait, hard)
28 */ 27 */
29#include "platform.h" 28#include "platform.h"
30#include "gnunet_constants.h" 29#include "gnunet_constants.h"
@@ -32,7 +31,7 @@
32#include "fs.h" 31#include "fs.h"
33#include "fs_tree.h" 32#include "fs_tree.h"
34 33
35#define DEBUG_DOWNLOAD GNUNET_YES 34#define DEBUG_DOWNLOAD GNUNET_NO
36 35
37/** 36/**
38 * Determine if the given download (options and meta data) should cause 37 * Determine if the given download (options and meta data) should cause
@@ -415,6 +414,223 @@ match_full_data (void *cls,
415} 414}
416 415
417 416
417
418/**
419 * Closure for 'reconstruct_cont' and 'reconstruct_cb'.
420 */
421struct ReconstructContext
422{
423 /**
424 * File handle open for the reconstruction.
425 */
426 struct GNUNET_DISK_FileHandle *fh;
427
428 /**
429 * the download context.
430 */
431 struct GNUNET_FS_DownloadContext *dc;
432
433 /**
434 * Tree encoder used for the reconstruction.
435 */
436 struct GNUNET_FS_TreeEncoder *te;
437
438 /**
439 * CHK of block we are trying to reconstruct.
440 */
441 struct ContentHashKey chk;
442
443 /**
444 * Request that was generated.
445 */
446 struct DownloadRequest *sm;
447
448 /**
449 * Offset of block we are trying to reconstruct.
450 */
451 uint64_t offset;
452
453 /**
454 * Depth of block we are trying to reconstruct.
455 */
456 unsigned int depth;
457
458};
459
460
461/**
462 * Continuation after a possible attempt to reconstruct
463 * the current IBlock from the existing file.
464 *
465 * @param cls the 'struct ReconstructContext'
466 * @param tc scheduler context
467 */
468static void
469reconstruct_cont (void *cls,
470 const struct GNUNET_SCHEDULER_TaskContext *tc)
471{
472 struct ReconstructContext *rcc = cls;
473
474 if (rcc->te != NULL)
475 GNUNET_FS_tree_encoder_finish (rcc->te, NULL, NULL);
476 rcc->dc->reconstruct_failed = GNUNET_YES;
477 if (rcc->fh != NULL)
478 GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (rcc->fh));
479 if ( (rcc->dc->th == NULL) &&
480 (rcc->dc->client != NULL) )
481 {
482#if DEBUG_DOWNLOAD
483 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
484 "Asking for transmission to FS service\n");
485#endif
486 rcc->dc->th = GNUNET_CLIENT_notify_transmit_ready (rcc->dc->client,
487 sizeof (struct SearchMessage),
488 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
489 GNUNET_NO,
490 &transmit_download_request,
491 rcc->dc);
492 }
493 else
494 {
495#if DEBUG_DOWNLOAD
496 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
497 "Transmission request not issued (%p %p)\n",
498 rcc->dc->th,
499 rcc->dc->client);
500#endif
501 }
502 GNUNET_free (rcc);
503}
504
505
506static void
507get_next_block (void *cls,
508 const struct GNUNET_SCHEDULER_TaskContext *tc)
509{
510 struct ReconstructContext *rcc = cls;
511 GNUNET_FS_tree_encoder_next (rcc->te);
512}
513
514
515/**
516 * Function called asking for the current (encoded)
517 * block to be processed. After processing the
518 * client should either call "GNUNET_FS_tree_encode_next"
519 * or (on error) "GNUNET_FS_tree_encode_finish".
520 *
521 * This function checks if the content on disk matches
522 * the expected content based on the URI.
523 *
524 * @param cls closure
525 * @param query the query for the block (key for lookup in the datastore)
526 * @param offset offset of the block
527 * @param type type of the block (IBLOCK or DBLOCK)
528 * @param block the (encrypted) block
529 * @param block_size size of block (in bytes)
530 */
531static void
532reconstruct_cb (void *cls,
533 const GNUNET_HashCode *query,
534 uint64_t offset,
535 unsigned int depth,
536 enum GNUNET_BLOCK_Type type,
537 const void *block,
538 uint16_t block_size)
539{
540 struct ReconstructContext *rcc = cls;
541 struct ProcessResultClosure prc;
542 struct GNUNET_FS_TreeEncoder *te;
543 uint64_t off;
544 uint64_t boff;
545 uint64_t roff;
546 unsigned int i;
547
548 roff = offset / DBLOCK_SIZE;
549 for (i=rcc->dc->treedepth;i>depth;i--)
550 roff /= CHK_PER_INODE;
551 boff = roff * DBLOCK_SIZE;
552 for (i=rcc->dc->treedepth;i>depth;i--)
553 boff *= CHK_PER_INODE;
554 /* convert reading offset into IBLOCKs on-disk offset */
555 off = compute_disk_offset (GNUNET_FS_uri_chk_get_file_size (rcc->dc->uri),
556 boff,
557 depth,
558 rcc->dc->treedepth);
559 if ( (off == rcc->offset) &&
560 (depth == rcc->depth) &&
561 (0 == memcmp (query,
562 &rcc->chk.query,
563 sizeof (GNUNET_HashCode))) )
564 {
565 /* already got it! */
566 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
567 _("Block reconstruction at offset %llu and depth %u successful\n"),
568 (unsigned long long) offset,
569 depth);
570 prc.dc = rcc->dc;
571 prc.data = block;
572 prc.size = block_size;
573 prc.type = type;
574 prc.query = rcc->chk.query;
575 prc.do_store = GNUNET_NO;
576 process_result_with_request (&prc,
577 &rcc->chk.key,
578 rcc->sm);
579 te = rcc->te;
580 rcc->te = NULL;
581 GNUNET_FS_tree_encoder_finish (te, NULL, NULL);
582 GNUNET_free (rcc);
583 return;
584 }
585 GNUNET_SCHEDULER_add_continuation (&get_next_block,
586 rcc,
587 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
588}
589
590
591/**
592 * Function called by the tree encoder to obtain
593 * a block of plaintext data (for the lowest level
594 * of the tree).
595 *
596 * @param cls our 'struct ReconstructContext'
597 * @param offset identifies which block to get
598 * @param max (maximum) number of bytes to get; returning
599 * fewer will also cause errors
600 * @param buf where to copy the plaintext buffer
601 * @param emsg location to store an error message (on error)
602 * @return number of bytes copied to buf, 0 on error
603 */
604static size_t
605fh_reader (void *cls,
606 uint64_t offset,
607 size_t max,
608 void *buf,
609 char **emsg)
610{
611 struct ReconstructContext *rcc = cls;
612 struct GNUNET_DISK_FileHandle *fh = rcc->fh;
613 ssize_t ret;
614
615 *emsg = NULL;
616 if (offset !=
617 GNUNET_DISK_file_seek (fh,
618 offset,
619 GNUNET_DISK_SEEK_SET))
620 {
621 *emsg = GNUNET_strdup (strerror (errno));
622 return 0;
623 }
624 ret = GNUNET_DISK_file_read (fh, buf, max);
625 if (ret < 0)
626 {
627 *emsg = GNUNET_strdup (strerror (errno));
628 return 0;
629 }
630 return ret;
631}
632
633
418/** 634/**
419 * Schedule the download of the specified block in the tree. 635 * Schedule the download of the specified block in the tree.
420 * 636 *
@@ -440,8 +656,9 @@ schedule_block_download (struct GNUNET_FS_DownloadContext *dc,
440 GNUNET_HashCode key; 656 GNUNET_HashCode key;
441 struct MatchDataContext mdc; 657 struct MatchDataContext mdc;
442 struct GNUNET_DISK_FileHandle *fh; 658 struct GNUNET_DISK_FileHandle *fh;
659 struct ReconstructContext *rcc;
443 660
444 total = GNUNET_ntohll (dc->uri->data.chk.file_length); 661 total = GNUNET_FS_uri_chk_get_file_size (dc->uri);
445 len = GNUNET_FS_tree_calculate_block_size (total, 662 len = GNUNET_FS_tree_calculate_block_size (total,
446 dc->treedepth, 663 dc->treedepth,
447 offset, 664 offset,
@@ -485,12 +702,15 @@ schedule_block_download (struct GNUNET_FS_DownloadContext *dc,
485 GNUNET_h2s (&chk->query)); 702 GNUNET_h2s (&chk->query));
486#endif 703#endif
487 fh = NULL; 704 fh = NULL;
488 if ( (dc->old_file_size > off) && 705 if ( ( (dc->old_file_size > off) ||
706 ( (depth < dc->treedepth) &&
707 (dc->reconstruct_failed == GNUNET_NO) ) ) &&
489 (dc->filename != NULL) ) 708 (dc->filename != NULL) )
490 fh = GNUNET_DISK_file_open (dc->filename, 709 fh = GNUNET_DISK_file_open (dc->filename,
491 GNUNET_DISK_OPEN_READ, 710 GNUNET_DISK_OPEN_READ,
492 GNUNET_DISK_PERM_NONE); 711 GNUNET_DISK_PERM_NONE);
493 if ( (fh != NULL) && 712 if ( (fh != NULL) &&
713 (dc->old_file_size > off) &&
494 (off == 714 (off ==
495 GNUNET_DISK_file_seek (fh, 715 GNUNET_DISK_file_seek (fh,
496 off, 716 off,
@@ -517,46 +737,31 @@ schedule_block_download (struct GNUNET_FS_DownloadContext *dc,
517 return; 737 return;
518 } 738 }
519 } 739 }
520 if (fh != NULL) 740 rcc = GNUNET_malloc (sizeof (struct ReconstructContext));
521 GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fh)); 741 rcc->fh = fh;
522 if (depth < dc->treedepth) 742 rcc->dc = dc;
523 { 743 rcc->sm = sm;
524 // FIXME: try if we could 744 rcc->chk = *chk;
525 // reconstitute this IBLOCK 745 rcc->offset = off;
526 // from the existing blocks on disk (can wait) 746 rcc->depth = depth;
527 // (read block(s), encode, compare with 747 if ( (depth < dc->treedepth) &&
528 // query; if matches, simply return) 748 (dc->reconstruct_failed == GNUNET_NO) &&
529 } 749 (fh != NULL) )
530
531 if ( (dc->th == NULL) &&
532 (dc->client != NULL) )
533 {
534#if DEBUG_DOWNLOAD
535 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
536 "Asking for transmission to FS service\n");
537#endif
538 dc->th = GNUNET_CLIENT_notify_transmit_ready (dc->client,
539 sizeof (struct SearchMessage),
540 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
541 GNUNET_NO,
542 &transmit_download_request,
543 dc);
544 }
545 else
546 { 750 {
547#if DEBUG_DOWNLOAD 751 rcc->te = GNUNET_FS_tree_encoder_create (dc->h,
548 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 752 dc->old_file_size,
549 "Transmission request not issued (%p %p)\n", 753 rcc,
550 dc->th, 754 fh_reader,
551 dc->client); 755 &reconstruct_cb,
552#endif 756 NULL,
553 757 &reconstruct_cont);
758 GNUNET_FS_tree_encoder_next (rcc->te);
759 return;
554 } 760 }
555 761 reconstruct_cont (rcc, NULL);
556} 762}
557 763
558 764
559
560/** 765/**
561 * Suggest a filename based on given metadata. 766 * Suggest a filename based on given metadata.
562 * 767 *
@@ -1624,6 +1829,29 @@ deactivate_fs_download (void *cls)
1624 1829
1625 1830
1626/** 1831/**
1832 * Task that creates the initial (top-level) download
1833 * request for the file.
1834 *
1835 * @param cls the 'struct GNUNET_FS_DownloadContext'
1836 * @param tc scheduler context
1837 */
1838void
1839GNUNET_FS_download_start_task_ (void *cls,
1840 const struct GNUNET_SCHEDULER_TaskContext *tc)
1841{
1842 struct GNUNET_FS_DownloadContext *dc = cls;
1843
1844 dc->start_task = GNUNET_SCHEDULER_NO_TASK;
1845 schedule_block_download (dc,
1846 (dc->uri->type == chk)
1847 ? &dc->uri->data.chk.chk
1848 : &dc->uri->data.loc.fi.chk,
1849 0,
1850 1 /* 0 == CHK, 1 == top */);
1851}
1852
1853
1854/**
1627 * Create SUSPEND event for the given download operation 1855 * Create SUSPEND event for the given download operation
1628 * and then clean up our state (without stop signal). 1856 * and then clean up our state (without stop signal).
1629 * 1857 *
@@ -1634,7 +1862,12 @@ GNUNET_FS_download_signal_suspend_ (void *cls)
1634{ 1862{
1635 struct GNUNET_FS_DownloadContext *dc = cls; 1863 struct GNUNET_FS_DownloadContext *dc = cls;
1636 struct GNUNET_FS_ProgressInfo pi; 1864 struct GNUNET_FS_ProgressInfo pi;
1637 1865
1866 if (dc->start_task != GNUNET_SCHEDULER_NO_TASK)
1867 {
1868 GNUNET_SCHEDULER_cancel (dc->start_task);
1869 dc->start_task = GNUNET_SCHEDULER_NO_TASK;
1870 }
1638 if (dc->top != NULL) 1871 if (dc->top != NULL)
1639 GNUNET_FS_end_top (dc->h, dc->top); 1872 GNUNET_FS_end_top (dc->h, dc->top);
1640 while (NULL != dc->child_head) 1873 while (NULL != dc->child_head)
@@ -1785,12 +2018,7 @@ GNUNET_FS_download_start (struct GNUNET_FS_Handle *h,
1785 pi.status = GNUNET_FS_STATUS_DOWNLOAD_START; 2018 pi.status = GNUNET_FS_STATUS_DOWNLOAD_START;
1786 pi.value.download.specifics.start.meta = meta; 2019 pi.value.download.specifics.start.meta = meta;
1787 GNUNET_FS_download_make_status_ (&pi, dc); 2020 GNUNET_FS_download_make_status_ (&pi, dc);
1788 schedule_block_download (dc, 2021 dc->start_task = GNUNET_SCHEDULER_add_now (&GNUNET_FS_download_start_task_, dc);
1789 (dc->uri->type == chk)
1790 ? &dc->uri->data.chk.chk
1791 : &dc->uri->data.loc.fi.chk,
1792 0,
1793 1 /* 0 == CHK, 1 == top */);
1794 GNUNET_FS_download_sync_ (dc); 2022 GNUNET_FS_download_sync_ (dc);
1795 GNUNET_FS_download_start_downloading_ (dc); 2023 GNUNET_FS_download_start_downloading_ (dc);
1796 return dc; 2024 return dc;
@@ -1913,16 +2141,12 @@ GNUNET_FS_download_start_from_search (struct GNUNET_FS_Handle *h,
1913 pi.status = GNUNET_FS_STATUS_DOWNLOAD_START; 2141 pi.status = GNUNET_FS_STATUS_DOWNLOAD_START;
1914 pi.value.download.specifics.start.meta = dc->meta; 2142 pi.value.download.specifics.start.meta = dc->meta;
1915 GNUNET_FS_download_make_status_ (&pi, dc); 2143 GNUNET_FS_download_make_status_ (&pi, dc);
1916 schedule_block_download (dc, 2144 dc->start_task = GNUNET_SCHEDULER_add_now (&GNUNET_FS_download_start_task_, dc);
1917 &dc->uri->data.chk.chk,
1918 0,
1919 1 /* 0 == CHK, 1 == top */);
1920 GNUNET_FS_download_sync_ (dc); 2145 GNUNET_FS_download_sync_ (dc);
1921 GNUNET_FS_download_start_downloading_ (dc); 2146 GNUNET_FS_download_start_downloading_ (dc);
1922 return dc; 2147 return dc;
1923} 2148}
1924 2149
1925
1926/** 2150/**
1927 * Start the downloading process (by entering the queue). 2151 * Start the downloading process (by entering the queue).
1928 * 2152 *
@@ -1931,6 +2155,8 @@ GNUNET_FS_download_start_from_search (struct GNUNET_FS_Handle *h,
1931void 2155void
1932GNUNET_FS_download_start_downloading_ (struct GNUNET_FS_DownloadContext *dc) 2156GNUNET_FS_download_start_downloading_ (struct GNUNET_FS_DownloadContext *dc)
1933{ 2157{
2158 if (dc->completed == dc->length)
2159 return;
1934 GNUNET_assert (dc->job_queue == NULL); 2160 GNUNET_assert (dc->job_queue == NULL);
1935 dc->job_queue = GNUNET_FS_queue_ (dc->h, 2161 dc->job_queue = GNUNET_FS_queue_ (dc->h,
1936 &activate_fs_download, 2162 &activate_fs_download,
@@ -1955,6 +2181,11 @@ GNUNET_FS_download_stop (struct GNUNET_FS_DownloadContext *dc,
1955 2181
1956 if (dc->top != NULL) 2182 if (dc->top != NULL)
1957 GNUNET_FS_end_top (dc->h, dc->top); 2183 GNUNET_FS_end_top (dc->h, dc->top);
2184 if (dc->start_task != GNUNET_SCHEDULER_NO_TASK)
2185 {
2186 GNUNET_SCHEDULER_cancel (dc->start_task);
2187 dc->start_task = GNUNET_SCHEDULER_NO_TASK;
2188 }
1958 if (dc->search != NULL) 2189 if (dc->search != NULL)
1959 { 2190 {
1960 dc->search->download = NULL; 2191 dc->search->download = NULL;