diff options
author | Christian Grothoff <christian@grothoff.org> | 2009-09-05 21:39:13 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2009-09-05 21:39:13 +0000 |
commit | 40b39eeabe0f8301cc7410c9b54f82dd46c48cbb (patch) | |
tree | ef59540033927be735b295f8c0f05dd501098e7f /src | |
parent | 0dfe519c70ef2c40c8f63499c521c0885af37cc2 (diff) | |
download | gnunet-40b39eeabe0f8301cc7410c9b54f82dd46c48cbb.tar.gz gnunet-40b39eeabe0f8301cc7410c9b54f82dd46c48cbb.zip |
towards having download
Diffstat (limited to 'src')
-rw-r--r-- | src/fs/fs.h | 8 | ||||
-rw-r--r-- | src/fs/fs_download.c | 210 |
2 files changed, 157 insertions, 61 deletions
diff --git a/src/fs/fs.h b/src/fs/fs.h index 529a917a3..50090c6fd 100644 --- a/src/fs/fs.h +++ b/src/fs/fs.h | |||
@@ -877,6 +877,14 @@ struct GNUNET_FS_DownloadContext | |||
877 | GNUNET_SCHEDULER_TaskIdentifier task; | 877 | GNUNET_SCHEDULER_TaskIdentifier task; |
878 | 878 | ||
879 | /** | 879 | /** |
880 | * What was the size of the file on disk that we're downloading | ||
881 | * before we started? Used to detect if there is a point in | ||
882 | * checking an existing block on disk for matching the desired | ||
883 | * content. 0 if the file did not exist already. | ||
884 | */ | ||
885 | uint64_t old_file_size; | ||
886 | |||
887 | /** | ||
880 | * What is the first offset that we're interested | 888 | * What is the first offset that we're interested |
881 | * in? | 889 | * in? |
882 | */ | 890 | */ |
diff --git a/src/fs/fs_download.c b/src/fs/fs_download.c index 904244dbb..c5bfec52c 100644 --- a/src/fs/fs_download.c +++ b/src/fs/fs_download.c | |||
@@ -23,9 +23,9 @@ | |||
23 | * @author Christian Grothoff | 23 | * @author Christian Grothoff |
24 | * | 24 | * |
25 | * TODO: | 25 | * TODO: |
26 | * - process replies | 26 | * - offset calculations |
27 | * - callback signaling | 27 | * - callback signaling |
28 | * - check if blocks exist already | 28 | * - check if blocks exist already (can wait) |
29 | * - location URI suppport (can wait) | 29 | * - location URI suppport (can wait) |
30 | * - persistence (can wait) | 30 | * - persistence (can wait) |
31 | */ | 31 | */ |
@@ -37,6 +37,65 @@ | |||
37 | 37 | ||
38 | #define DEBUG_DOWNLOAD GNUNET_YES | 38 | #define DEBUG_DOWNLOAD GNUNET_YES |
39 | 39 | ||
40 | /** | ||
41 | * We're storing the IBLOCKS after the | ||
42 | * DBLOCKS on disk (so that we only have | ||
43 | * to truncate the file once we're done). | ||
44 | * | ||
45 | * Given the offset of a block (with respect | ||
46 | * to the DBLOCKS) and its depth, return the | ||
47 | * offset where we would store this block | ||
48 | * in the file. | ||
49 | * | ||
50 | * @param fsize overall file size | ||
51 | * @param off offset of the block in the file | ||
52 | * @param depth depth of the block in the tree | ||
53 | * @param treedepth maximum depth of the tree | ||
54 | * @return off for DBLOCKS (depth == treedepth), | ||
55 | * otherwise an offset past the end | ||
56 | * of the file that does not overlap | ||
57 | * with the range for any other block | ||
58 | */ | ||
59 | static uint64_t | ||
60 | compute_disk_offset (uint64_t fsize, | ||
61 | uint64_t off, | ||
62 | unsigned int depth, | ||
63 | unsigned int treedepth) | ||
64 | { | ||
65 | if (depth == treedepth) | ||
66 | return off; | ||
67 | return 42; // FIXME | ||
68 | } | ||
69 | |||
70 | /** | ||
71 | * Given a file of the specified treedepth and | ||
72 | * a block at the given offset and depth, | ||
73 | * calculate the offset for the CHK at | ||
74 | * the given index. | ||
75 | * | ||
76 | * @param offset the offset of the first | ||
77 | * DBLOCK in the subtree of the | ||
78 | * identified IBLOCK | ||
79 | * @param depth the depth of the IBLOCK in the tree | ||
80 | * @param treedepth overall depth of the tree | ||
81 | * @param i which CHK in the IBLOCK are we | ||
82 | * talking about | ||
83 | * @return offset if i=0, otherwise an appropriately | ||
84 | * larger value (i.e., if depth = treedepth-1, | ||
85 | * the returned value should be offset+DBLOCK_SIZE) | ||
86 | */ | ||
87 | static uint64_t | ||
88 | compute_dblock_offset (uint64_t offset, | ||
89 | unsigned int depth, | ||
90 | unsigned int treedepth, | ||
91 | unsigned int i) | ||
92 | { | ||
93 | GNUNET_assert (depth < treedepth); | ||
94 | if (i == 0) | ||
95 | return offset; | ||
96 | return 42; // FIXME | ||
97 | } | ||
98 | |||
40 | 99 | ||
41 | /** | 100 | /** |
42 | * Schedule the download of the specified | 101 | * Schedule the download of the specified |
@@ -57,8 +116,31 @@ schedule_block_download (struct GNUNET_FS_DownloadContext *dc, | |||
57 | unsigned int depth) | 116 | unsigned int depth) |
58 | { | 117 | { |
59 | struct DownloadRequest *sm; | 118 | struct DownloadRequest *sm; |
60 | 119 | uint64_t off; | |
61 | // FIXME: check if block exists on disk! | 120 | |
121 | off = compute_disk_offset (GNUNET_ntohll (dc->uri->data.chk.file_length), | ||
122 | offset, | ||
123 | depth, | ||
124 | dc->treedepth); | ||
125 | if ( (dc->old_file_size > off) && | ||
126 | (dc->handle != NULL) && | ||
127 | (off == | ||
128 | GNUNET_DISK_file_seek (dc->handle, | ||
129 | off, | ||
130 | GNUNET_DISK_SEEK_SET) ) ) | ||
131 | { | ||
132 | // FIXME: check if block exists on disk! | ||
133 | // (read block, encode, compare with | ||
134 | // query; if matches, simply return) | ||
135 | } | ||
136 | if (depth < dc->treedepth) | ||
137 | { | ||
138 | // FIXME: try if we could | ||
139 | // reconstitute this IBLOCK | ||
140 | // from the existing blocks on disk (can wait) | ||
141 | // (read block(s), encode, compare with | ||
142 | // query; if matches, simply return) | ||
143 | } | ||
62 | sm = GNUNET_malloc (sizeof (struct DownloadRequest)); | 144 | sm = GNUNET_malloc (sizeof (struct DownloadRequest)); |
63 | sm->chk = *chk; | 145 | sm->chk = *chk; |
64 | sm->offset = offset; | 146 | sm->offset = offset; |
@@ -103,7 +185,12 @@ process_result (struct GNUNET_FS_DownloadContext *dc, | |||
103 | struct GNUNET_CRYPTO_AesSessionKey skey; | 185 | struct GNUNET_CRYPTO_AesSessionKey skey; |
104 | struct GNUNET_CRYPTO_AesInitializationVector iv; | 186 | struct GNUNET_CRYPTO_AesInitializationVector iv; |
105 | char pt[size]; | 187 | char pt[size]; |
188 | uint64_t off; | ||
189 | size_t app; | ||
190 | unsigned int i; | ||
191 | struct ContentHashKey *chk; | ||
106 | 192 | ||
193 | // FIXME: check that size is as big as expected, otherwise ignore!!! | ||
107 | GNUNET_CRYPTO_hash (data, size, &query); | 194 | GNUNET_CRYPTO_hash (data, size, &query); |
108 | sm = GNUNET_CONTAINER_multihashmap_get (dc->active, | 195 | sm = GNUNET_CONTAINER_multihashmap_get (dc->active, |
109 | &query); | 196 | &query); |
@@ -122,10 +209,62 @@ process_result (struct GNUNET_FS_DownloadContext *dc, | |||
122 | &skey, | 209 | &skey, |
123 | &iv, | 210 | &iv, |
124 | pt); | 211 | pt); |
125 | // FIXME: save to disk | 212 | /* save to disk */ |
213 | if ( (NULL != dc->handle) && | ||
214 | ( (sm->depth == dc->treedepth) || | ||
215 | (0 == (dc->options & GNUNET_FS_DOWNLOAD_NO_TEMPORARIES)) ) ) | ||
216 | { | ||
217 | off = compute_disk_offset (GNUNET_ntohll (dc->uri->data.chk.file_length), | ||
218 | sm->offset, | ||
219 | sm->depth, | ||
220 | dc->treedepth); | ||
221 | GNUNET_assert (off != | ||
222 | GNUNET_DISK_file_seek (dc->handle, | ||
223 | off, | ||
224 | GNUNET_DISK_SEEK_SET) ); | ||
225 | GNUNET_DISK_file_write (dc->handle, | ||
226 | pt, | ||
227 | size); | ||
228 | } | ||
126 | // FIXME: make persistent | 229 | // FIXME: make persistent |
230 | |||
231 | if (sm->depth == dc->treedepth) | ||
232 | { | ||
233 | app = size; | ||
234 | if (sm->offset < dc->offset) | ||
235 | { | ||
236 | /* starting offset begins in the middle of pt, | ||
237 | do not count first bytes as progress */ | ||
238 | GNUNET_assert (app > (dc->offset - sm->offset)); | ||
239 | app -= (dc->offset - sm->offset); | ||
240 | } | ||
241 | if (sm->offset + size > dc->offset + dc->length) | ||
242 | { | ||
243 | /* end of block is after relevant range, | ||
244 | do not count last bytes as progress */ | ||
245 | GNUNET_assert (app > (sm->offset + size) - (dc->offset + dc->length)); | ||
246 | app -= (sm->offset + size) - (dc->offset + dc->length); | ||
247 | } | ||
248 | dc->completed += app; | ||
249 | } | ||
127 | // FIXME: call progress callback | 250 | // FIXME: call progress callback |
128 | // FIXME: trigger next block (if applicable) | 251 | if (sm->depth == dc->treedepth) |
252 | return; | ||
253 | GNUNET_assert (0 == (size % sizeof(struct ContentHashKey))); | ||
254 | chk = (struct ContentHashKey*) pt; | ||
255 | for (i=0;i<(size / sizeof(struct ContentHashKey));i++) | ||
256 | { | ||
257 | off = compute_dblock_offset (sm->offset, | ||
258 | sm->depth, | ||
259 | dc->treedepth, | ||
260 | i); | ||
261 | if ( (off + DBLOCK_SIZE >= dc->offset) && | ||
262 | (off < dc->offset + dc->length) ) | ||
263 | schedule_block_download (dc, | ||
264 | &chk[i], | ||
265 | off, | ||
266 | sm->depth + 1); | ||
267 | } | ||
129 | } | 268 | } |
130 | 269 | ||
131 | 270 | ||
@@ -363,6 +502,10 @@ GNUNET_FS_file_download_start (struct GNUNET_FS_Handle *h, | |||
363 | if (NULL != filename) | 502 | if (NULL != filename) |
364 | { | 503 | { |
365 | dc->filename = GNUNET_strdup (filename); | 504 | dc->filename = GNUNET_strdup (filename); |
505 | if (GNUNET_YES == GNUNET_DISK_file_test (filename)) | ||
506 | GNUNET_DISK_file_size (filename, | ||
507 | &dc->old_file_size, | ||
508 | GNUNET_YES); | ||
366 | dc->handle = GNUNET_DISK_file_open (filename, | 509 | dc->handle = GNUNET_DISK_file_open (filename, |
367 | GNUNET_DISK_OPEN_READWRITE | | 510 | GNUNET_DISK_OPEN_READWRITE | |
368 | GNUNET_DISK_OPEN_CREATE, | 511 | GNUNET_DISK_OPEN_CREATE, |
@@ -581,61 +724,6 @@ check_node_present (const struct Node *node) | |||
581 | return ret; | 724 | return ret; |
582 | } | 725 | } |
583 | 726 | ||
584 | /** | ||
585 | * DOWNLOAD children of this GNUNET_EC_IBlock. | ||
586 | * | ||
587 | * @param node the node that should be downloaded | ||
588 | */ | ||
589 | static void | ||
590 | iblock_download_children (const struct Node *node, | ||
591 | const char *data, unsigned int size) | ||
592 | { | ||
593 | struct GNUNET_GE_Context *ectx = node->ctx->ectx; | ||
594 | int i; | ||
595 | struct Node *child; | ||
596 | unsigned int childcount; | ||
597 | const GNUNET_EC_ContentHashKey *chks; | ||
598 | unsigned int levelSize; | ||
599 | unsigned long long baseOffset; | ||
600 | |||
601 | GNUNET_GE_ASSERT (ectx, node->level > 0); | ||
602 | childcount = size / sizeof (GNUNET_EC_ContentHashKey); | ||
603 | if (size != childcount * sizeof (GNUNET_EC_ContentHashKey)) | ||
604 | { | ||
605 | GNUNET_GE_BREAK (ectx, 0); | ||
606 | return; | ||
607 | } | ||
608 | if (node->level == 1) | ||
609 | { | ||
610 | levelSize = GNUNET_ECRS_DBLOCK_SIZE; | ||
611 | baseOffset = | ||
612 | node->offset / sizeof (GNUNET_EC_ContentHashKey) * | ||
613 | GNUNET_ECRS_DBLOCK_SIZE; | ||
614 | } | ||
615 | else | ||
616 | { | ||
617 | levelSize = | ||
618 | sizeof (GNUNET_EC_ContentHashKey) * GNUNET_ECRS_CHK_PER_INODE; | ||
619 | baseOffset = node->offset * GNUNET_ECRS_CHK_PER_INODE; | ||
620 | } | ||
621 | chks = (const GNUNET_EC_ContentHashKey *) data; | ||
622 | for (i = 0; i < childcount; i++) | ||
623 | { | ||
624 | child = GNUNET_malloc (sizeof (struct Node)); | ||
625 | child->ctx = node->ctx; | ||
626 | child->chk = chks[i]; | ||
627 | child->offset = baseOffset + i * levelSize; | ||
628 | GNUNET_GE_ASSERT (ectx, child->offset < node->ctx->total); | ||
629 | child->level = node->level - 1; | ||
630 | GNUNET_GE_ASSERT (ectx, (child->level != 0) || | ||
631 | ((child->offset % GNUNET_ECRS_DBLOCK_SIZE) == 0)); | ||
632 | if (GNUNET_NO == check_node_present (child)) | ||
633 | add_request (child); | ||
634 | else | ||
635 | GNUNET_free (child); /* done already! */ | ||
636 | } | ||
637 | } | ||
638 | |||
639 | #endif | 727 | #endif |
640 | 728 | ||
641 | 729 | ||