diff options
Diffstat (limited to 'src/fs/fs_download.c')
-rw-r--r-- | src/fs/fs_download.c | 236 |
1 files changed, 132 insertions, 104 deletions
diff --git a/src/fs/fs_download.c b/src/fs/fs_download.c index 6e215ed27..eb45f795d 100644 --- a/src/fs/fs_download.c +++ b/src/fs/fs_download.c | |||
@@ -175,6 +175,61 @@ transmit_download_request (void *cls, | |||
175 | 175 | ||
176 | 176 | ||
177 | /** | 177 | /** |
178 | * Closure for iterator processing results. | ||
179 | */ | ||
180 | struct ProcessResultClosure | ||
181 | { | ||
182 | |||
183 | /** | ||
184 | * Hash of data. | ||
185 | */ | ||
186 | GNUNET_HashCode query; | ||
187 | |||
188 | /** | ||
189 | * Data found in P2P network. | ||
190 | */ | ||
191 | const void *data; | ||
192 | |||
193 | /** | ||
194 | * Our download context. | ||
195 | */ | ||
196 | struct GNUNET_FS_DownloadContext *dc; | ||
197 | |||
198 | /** | ||
199 | * Number of bytes in data. | ||
200 | */ | ||
201 | size_t size; | ||
202 | |||
203 | /** | ||
204 | * Type of data. | ||
205 | */ | ||
206 | uint32_t type; | ||
207 | |||
208 | /** | ||
209 | * Flag to indicate if this block should be stored on disk. | ||
210 | */ | ||
211 | int do_store; | ||
212 | |||
213 | }; | ||
214 | |||
215 | |||
216 | /** | ||
217 | * Iterator over entries in the pending requests in the 'active' map for the | ||
218 | * reply that we just got. | ||
219 | * | ||
220 | * @param cls closure (our 'struct ProcessResultClosure') | ||
221 | * @param key query for the given value / request | ||
222 | * @param value value in the hash map (a 'struct DownloadRequest') | ||
223 | * @return GNUNET_YES (we should continue to iterate); unless serious error | ||
224 | */ | ||
225 | static int | ||
226 | process_result_with_request (void *cls, | ||
227 | const GNUNET_HashCode * key, | ||
228 | void *value); | ||
229 | |||
230 | |||
231 | |||
232 | /** | ||
178 | * Schedule the download of the specified block in the tree. | 233 | * Schedule the download of the specified block in the tree. |
179 | * | 234 | * |
180 | * @param dc overall download this block belongs to | 235 | * @param dc overall download this block belongs to |
@@ -192,7 +247,12 @@ schedule_block_download (struct GNUNET_FS_DownloadContext *dc, | |||
192 | unsigned int depth) | 247 | unsigned int depth) |
193 | { | 248 | { |
194 | struct DownloadRequest *sm; | 249 | struct DownloadRequest *sm; |
250 | uint64_t total; | ||
195 | uint64_t off; | 251 | uint64_t off; |
252 | size_t len; | ||
253 | char block[DBLOCK_SIZE]; | ||
254 | GNUNET_HashCode key; | ||
255 | struct ProcessResultClosure prc; | ||
196 | 256 | ||
197 | #if DEBUG_DOWNLOAD | 257 | #if DEBUG_DOWNLOAD |
198 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 258 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
@@ -201,20 +261,77 @@ schedule_block_download (struct GNUNET_FS_DownloadContext *dc, | |||
201 | depth, | 261 | depth, |
202 | GNUNET_h2s (&chk->query)); | 262 | GNUNET_h2s (&chk->query)); |
203 | #endif | 263 | #endif |
204 | off = compute_disk_offset (GNUNET_ntohll (dc->uri->data.chk.file_length), | 264 | total = GNUNET_ntohll (dc->uri->data.chk.file_length); |
265 | off = compute_disk_offset (total, | ||
205 | offset, | 266 | offset, |
206 | depth, | 267 | depth, |
207 | dc->treedepth); | 268 | dc->treedepth); |
269 | len = GNUNET_FS_tree_calculate_block_size (total, | ||
270 | dc->treedepth, | ||
271 | offset, | ||
272 | depth); | ||
273 | sm = GNUNET_malloc (sizeof (struct DownloadRequest)); | ||
274 | sm->chk = *chk; | ||
275 | sm->offset = offset; | ||
276 | sm->depth = depth; | ||
277 | sm->is_pending = GNUNET_YES; | ||
278 | sm->next = dc->pending; | ||
279 | dc->pending = sm; | ||
280 | GNUNET_CONTAINER_multihashmap_put (dc->active, | ||
281 | &chk->query, | ||
282 | sm, | ||
283 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
284 | |||
208 | if ( (dc->old_file_size > off) && | 285 | if ( (dc->old_file_size > off) && |
209 | (dc->handle != NULL) && | 286 | (dc->handle != NULL) && |
210 | (off == | 287 | (off == |
211 | GNUNET_DISK_file_seek (dc->handle, | 288 | GNUNET_DISK_file_seek (dc->handle, |
212 | off, | 289 | off, |
213 | GNUNET_DISK_SEEK_SET) ) ) | 290 | GNUNET_DISK_SEEK_SET) ) && |
291 | (len == | ||
292 | GNUNET_DISK_file_read (dc->handle, | ||
293 | block, | ||
294 | len)) ) | ||
214 | { | 295 | { |
215 | // FIXME: check if block exists on disk! | 296 | /* FIXME: also check query matches!? */ |
216 | // (read block, encode, compare with | 297 | if (0 == memcmp (&key, |
217 | // query; if matches, simply return) | 298 | &chk->key, |
299 | sizeof (GNUNET_HashCode))) | ||
300 | { | ||
301 | char enc[len]; | ||
302 | struct GNUNET_CRYPTO_AesSessionKey sk; | ||
303 | struct GNUNET_CRYPTO_AesInitializationVector iv; | ||
304 | GNUNET_HashCode query; | ||
305 | |||
306 | GNUNET_CRYPTO_hash_to_aes_key (&key, &sk, &iv); | ||
307 | GNUNET_CRYPTO_aes_encrypt (block, len, | ||
308 | &sk, | ||
309 | &iv, | ||
310 | enc); | ||
311 | GNUNET_CRYPTO_hash (enc, len, &query); | ||
312 | if (0 == memcmp (&query, | ||
313 | &chk->query, | ||
314 | sizeof (GNUNET_HashCode))) | ||
315 | { | ||
316 | /* already got it! */ | ||
317 | prc.dc = dc; | ||
318 | prc.data = enc; | ||
319 | prc.size = len; | ||
320 | prc.type = (dc->treedepth == depth) | ||
321 | ? GNUNET_DATASTORE_BLOCKTYPE_DBLOCK | ||
322 | : GNUNET_DATASTORE_BLOCKTYPE_IBLOCK; | ||
323 | prc.query = chk->query; | ||
324 | prc.do_store = GNUNET_NO; /* useless */ | ||
325 | process_result_with_request (&prc, | ||
326 | &key, | ||
327 | sm); | ||
328 | } | ||
329 | else | ||
330 | { | ||
331 | GNUNET_break_op (0); | ||
332 | } | ||
333 | return; | ||
334 | } | ||
218 | } | 335 | } |
219 | if (depth < dc->treedepth) | 336 | if (depth < dc->treedepth) |
220 | { | 337 | { |
@@ -224,17 +341,6 @@ schedule_block_download (struct GNUNET_FS_DownloadContext *dc, | |||
224 | // (read block(s), encode, compare with | 341 | // (read block(s), encode, compare with |
225 | // query; if matches, simply return) | 342 | // query; if matches, simply return) |
226 | } | 343 | } |
227 | sm = GNUNET_malloc (sizeof (struct DownloadRequest)); | ||
228 | sm->chk = *chk; | ||
229 | sm->offset = offset; | ||
230 | sm->depth = depth; | ||
231 | sm->is_pending = GNUNET_YES; | ||
232 | sm->next = dc->pending; | ||
233 | dc->pending = sm; | ||
234 | GNUNET_CONTAINER_multihashmap_put (dc->active, | ||
235 | &chk->query, | ||
236 | sm, | ||
237 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
238 | 344 | ||
239 | if ( (dc->th == NULL) && | 345 | if ( (dc->th == NULL) && |
240 | (dc->client != NULL) ) | 346 | (dc->client != NULL) ) |
@@ -395,85 +501,6 @@ try_reconnect (struct GNUNET_FS_DownloadContext *dc); | |||
395 | 501 | ||
396 | 502 | ||
397 | /** | 503 | /** |
398 | * Compute how many bytes of data should be stored in | ||
399 | * the specified node. | ||
400 | * | ||
401 | * @param fsize overall file size | ||
402 | * @param totaldepth depth of the entire tree | ||
403 | * @param offset offset of the node | ||
404 | * @param depth depth of the node | ||
405 | * @return number of bytes stored in this node | ||
406 | */ | ||
407 | static size_t | ||
408 | calculate_block_size (uint64_t fsize, | ||
409 | unsigned int totaldepth, | ||
410 | uint64_t offset, | ||
411 | unsigned int depth) | ||
412 | { | ||
413 | unsigned int i; | ||
414 | size_t ret; | ||
415 | uint64_t rsize; | ||
416 | uint64_t epos; | ||
417 | unsigned int chks; | ||
418 | |||
419 | GNUNET_assert (offset < fsize); | ||
420 | if (depth == totaldepth) | ||
421 | { | ||
422 | ret = DBLOCK_SIZE; | ||
423 | if (offset + ret > fsize) | ||
424 | ret = (size_t) (fsize - offset); | ||
425 | return ret; | ||
426 | } | ||
427 | |||
428 | rsize = DBLOCK_SIZE; | ||
429 | for (i = totaldepth-1; i > depth; i--) | ||
430 | rsize *= CHK_PER_INODE; | ||
431 | epos = offset + rsize * CHK_PER_INODE; | ||
432 | GNUNET_assert (epos > offset); | ||
433 | if (epos > fsize) | ||
434 | epos = fsize; | ||
435 | /* round up when computing #CHKs in our IBlock */ | ||
436 | chks = (epos - offset + rsize - 1) / rsize; | ||
437 | GNUNET_assert (chks <= CHK_PER_INODE); | ||
438 | return chks * sizeof (struct ContentHashKey); | ||
439 | } | ||
440 | |||
441 | |||
442 | /** | ||
443 | * Closure for iterator processing results. | ||
444 | */ | ||
445 | struct ProcessResultClosure | ||
446 | { | ||
447 | |||
448 | /** | ||
449 | * Hash of data. | ||
450 | */ | ||
451 | GNUNET_HashCode query; | ||
452 | |||
453 | /** | ||
454 | * Data found in P2P network. | ||
455 | */ | ||
456 | const void *data; | ||
457 | |||
458 | /** | ||
459 | * Our download context. | ||
460 | */ | ||
461 | struct GNUNET_FS_DownloadContext *dc; | ||
462 | |||
463 | /** | ||
464 | * Number of bytes in data. | ||
465 | */ | ||
466 | size_t size; | ||
467 | |||
468 | /** | ||
469 | * Type of data. | ||
470 | */ | ||
471 | uint32_t type; | ||
472 | |||
473 | }; | ||
474 | |||
475 | |||
476 | /** | ||
477 | * We found an entry in a directory. Check if the respective child | 504 | * We found an entry in a directory. Check if the respective child |
478 | * already exists and if not create the respective child download. | 505 | * already exists and if not create the respective child download. |
479 | * | 506 | * |
@@ -764,23 +791,22 @@ process_result_with_request (void *cls, | |||
764 | char pt[prc->size]; | 791 | char pt[prc->size]; |
765 | struct GNUNET_FS_ProgressInfo pi; | 792 | struct GNUNET_FS_ProgressInfo pi; |
766 | uint64_t off; | 793 | uint64_t off; |
794 | size_t bs; | ||
767 | size_t app; | 795 | size_t app; |
768 | int i; | 796 | int i; |
769 | struct ContentHashKey *chk; | 797 | struct ContentHashKey *chk; |
770 | char *emsg; | 798 | char *emsg; |
771 | 799 | ||
772 | if (prc->size != calculate_block_size (GNUNET_ntohll (dc->uri->data.chk.file_length), | 800 | bs = GNUNET_FS_tree_calculate_block_size (GNUNET_ntohll (dc->uri->data.chk.file_length), |
773 | dc->treedepth, | 801 | dc->treedepth, |
774 | sm->offset, | 802 | sm->offset, |
775 | sm->depth)) | 803 | sm->depth); |
804 | if (prc->size != bs) | ||
776 | { | 805 | { |
777 | #if DEBUG_DOWNLOAD | 806 | #if DEBUG_DOWNLOAD |
778 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 807 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
779 | "Internal error or bogus download URI (expected %u bytes, got %u)\n", | 808 | "Internal error or bogus download URI (expected %u bytes, got %u)\n", |
780 | calculate_block_size (GNUNET_ntohll (dc->uri->data.chk.file_length), | 809 | bs, |
781 | dc->treedepth, | ||
782 | sm->offset, | ||
783 | sm->depth), | ||
784 | prc->size); | 810 | prc->size); |
785 | #endif | 811 | #endif |
786 | dc->emsg = GNUNET_strdup ("Internal error or bogus download URI"); | 812 | dc->emsg = GNUNET_strdup ("Internal error or bogus download URI"); |
@@ -815,7 +841,8 @@ process_result_with_request (void *cls, | |||
815 | sm->depth, | 841 | sm->depth, |
816 | dc->treedepth); | 842 | dc->treedepth); |
817 | /* save to disk */ | 843 | /* save to disk */ |
818 | if ( (NULL != dc->handle) && | 844 | if ( ( GNUNET_YES == prc->do_store) && |
845 | (NULL != dc->handle) && | ||
819 | ( (sm->depth == dc->treedepth) || | 846 | ( (sm->depth == dc->treedepth) || |
820 | (0 == (dc->options & GNUNET_FS_DOWNLOAD_NO_TEMPORARIES)) ) ) | 847 | (0 == (dc->options & GNUNET_FS_DOWNLOAD_NO_TEMPORARIES)) ) ) |
821 | { | 848 | { |
@@ -1006,6 +1033,7 @@ process_result (struct GNUNET_FS_DownloadContext *dc, | |||
1006 | prc.data = data; | 1033 | prc.data = data; |
1007 | prc.size = size; | 1034 | prc.size = size; |
1008 | prc.type = type; | 1035 | prc.type = type; |
1036 | prc.do_store = GNUNET_YES; | ||
1009 | GNUNET_CRYPTO_hash (data, size, &prc.query); | 1037 | GNUNET_CRYPTO_hash (data, size, &prc.query); |
1010 | #if DEBUG_DOWNLOAD | 1038 | #if DEBUG_DOWNLOAD |
1011 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1039 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |