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.c236
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 */
180struct 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 */
225static int
226process_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 */
407static size_t
408calculate_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 */
445struct 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,