*
* TODO:
* - different priority for scheduling probe downloads?
- * - download seems to not always find (or at least use!) embedded full data
*/
#include "platform.h"
#include "gnunet_constants.h"
}
-/**
- * Given a block at the given offset and depth, calculate the offset
- * for the CHK at the given index.
- *
- * @param offset the offset of the first
- * DBLOCK in the subtree of the
- * identified IBLOCK
- * @param depth the depth of the IBLOCK in the tree, 0 for DBLOCK
- * @param k which CHK in the IBLOCK are we
- * talking about
- * @return offset if k=0, otherwise an appropriately
- * larger value (i.e., if depth = 1,
- * the returned value should be offset+k*DBLOCK_SIZE)
- */
-static uint64_t
-compute_dblock_offset (uint64_t offset,
- unsigned int depth,
- unsigned int k)
-{
- unsigned int i;
- uint64_t lsize; /* what is the size of the sum of all DBlocks
- that a CHK at depth i corresponds to? */
-
- if (depth == 0)
- return offset;
- lsize = DBLOCK_SIZE;
- for (i=1;i<depth;i++)
- lsize *= CHK_PER_INODE;
- return offset + k * lsize;
-}
-
-
/**
* Fill in all of the generic fields for a download event and call the
* callback.
}
/* All of our children are done, so mark this download done */
dc->has_finished = GNUNET_YES;
+ if (dc->job_queue != NULL)
+ {
+ GNUNET_FS_dequeue_ (dc->job_queue);
+ dc->job_queue = NULL;
+ }
GNUNET_FS_download_sync_ (dc);
/* signal completion */
* Try it for upward reconstruction of the data. On success,
* the top-level block will move to state BRS_DOWNLOAD_UP.
*
- * @param dr one of our request entries
+ * @param dc context for the download
+ * @param dr download request to match against
* @param data plaintext data, starting from the beginning of the file
* @param data_len number of bytes in data
*/
pi.value.download.specifics.progress.data_len = dlen;
pi.value.download.specifics.progress.depth = 0;
GNUNET_FS_download_make_status_ (&pi, dc);
- if (0 != truncate (dc->filename,
- GNUNET_ntohll (dc->uri->data.chk.file_length)))
+ if ( (NULL != dc->filename) &&
+ (0 != truncate (dc->filename,
+ GNUNET_ntohll (dc->uri->data.chk.file_length))) )
GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
"truncate",
dc->filename);
child_block_size = GNUNET_FS_tree_compute_tree_size (drc->depth);
GNUNET_assert (0 == (drc->offset - dr->offset) % child_block_size);
chk_off = (drc->offset - dr->offset) / child_block_size;
- GNUNET_assert (drc->state == BRS_INIT);
- drc->state = BRS_CHK_SET;
- drc->chk = chks[chk_off];
- try_top_down_reconstruction (dc, drc);
+ if (drc->state == BRS_INIT)
+ {
+ drc->state = BRS_CHK_SET;
+ drc->chk = chks[chk_off];
+ try_top_down_reconstruction (dc, drc);
+ }
if (drc->state != BRS_DOWNLOAD_UP)
up_done = GNUNET_NO; /* children not all done */
}
* Schedule the download of the specified block in the tree.
*
* @param dc overall download this block belongs to
- * @param chk content-hash-key of the block
- * @param offset offset of the block in the file
- * (for IBlocks, the offset is the lowest
- * offset of any DBlock in the subtree under
- * the IBlock)
- * @param depth depth of the block, 0 is the root of the tree
+ * @param dr request to schedule
*/
static void
schedule_block_download (struct GNUNET_FS_DownloadContext *dc,
dr->depth,
GNUNET_h2s (&dr->chk.query));
#endif
- GNUNET_CONTAINER_DLL_insert (dc->pending_head,
- dc->pending_tail,
- dr);
- dr->is_pending = GNUNET_YES;
+ if (GNUNET_NO !=
+ GNUNET_CONTAINER_multihashmap_contains_value (dc->active,
+ &dr->chk.query,
+ dr))
+ return; /* already active */
GNUNET_CONTAINER_multihashmap_put (dc->active,
&dr->chk.query,
dr,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
if (dc->client == NULL)
return; /* download not active */
+ GNUNET_CONTAINER_DLL_insert (dc->pending_head,
+ dc->pending_tail,
+ dr);
+ dr->is_pending = GNUNET_YES;
if (NULL == dc->th)
dc->th = GNUNET_CLIENT_notify_transmit_ready (dc->client,
sizeof (struct SearchMessage),
{
struct GNUNET_FS_DownloadContext *dc = cls;
struct GNUNET_FS_DownloadContext *cpos;
- struct GNUNET_DISK_FileHandle *fh;
char *temp_name;
- const char *real_name;
char *fn;
char *us;
char *ext;
char *dn;
char *pos;
char *full_name;
+ char *sfn;
if (NULL == uri)
return; /* entry for the directory itself */
(NULL !=
strstr (dn + strlen(dn) - strlen(GNUNET_FS_DIRECTORY_EXT),
GNUNET_FS_DIRECTORY_EXT)) );
+ sfn = GNUNET_strdup (filename);
+ while ( (strlen (sfn) > 0) &&
+ (filename[strlen(sfn)-1] == '/') )
+ sfn[strlen(sfn)-1] = '\0';
if ( (strlen (dn) >= strlen (GNUNET_FS_DIRECTORY_EXT)) &&
(NULL !=
strstr (dn + strlen(dn) - strlen(GNUNET_FS_DIRECTORY_EXT),
"%s%s%s%s",
dn,
DIR_SEPARATOR_STR,
- filename,
+ sfn,
GNUNET_FS_DIRECTORY_EXT);
}
else
"%s%s%s",
dn,
DIR_SEPARATOR_STR,
- filename);
+ sfn);
}
+ GNUNET_free (sfn);
GNUNET_free (dn);
}
if ( (full_name != NULL) &&
}
temp_name = NULL;
- if ( (data != NULL) &&
- (GNUNET_FS_uri_chk_get_file_size (uri) == length) )
- {
- if (full_name == NULL)
- {
- temp_name = GNUNET_DISK_mktemp ("gnunet-download-trd");
- real_name = temp_name;
- }
- else
- {
- real_name = full_name;
- }
- /* write to disk, then trigger normal download which will instantly progress to completion */
- fh = GNUNET_DISK_file_open (real_name,
- GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE | GNUNET_DISK_OPEN_CREATE,
- GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
- if (fh == NULL)
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
- "open",
- real_name);
- GNUNET_free (full_name);
- GNUNET_free_non_null (fn);
- return;
- }
- if (length !=
- GNUNET_DISK_file_write (fh,
- data,
- length))
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
- "write",
- full_name);
- }
- GNUNET_DISK_file_close (fh);
- }
#if DEBUG_DOWNLOAD
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Triggering recursive download of size %llu with %u bytes MD\n",
pi.value.download.specifics.progress.depth = dr->depth;
GNUNET_FS_download_make_status_ (&pi, dc);
GNUNET_assert (dc->completed <= dc->length);
+ if (dr->depth == 0)
+ propagate_up (dr);
if (dc->completed == dc->length)
{
"truncate",
dc->filename);
}
- if (dc->job_queue != NULL)
- {
- GNUNET_FS_dequeue_ (dc->job_queue);
- dc->job_queue = NULL;
- }
GNUNET_assert (dr->depth == 0);
check_completed (dc);
}
if (dr->depth == 0)
{
- propagate_up (dr);
/* bottom of the tree, no child downloads possible, just sync */
GNUNET_FS_download_sync_ (dc);
return GNUNET_YES;
chk = (struct ContentHashKey*) pt;
for (i=(prc->size / sizeof(struct ContentHashKey))-1;i>=0;i--)
{
- off = compute_dblock_offset (dr->offset,
- dr->depth,
- i);
drc = dr->children[i];
switch (drc->state)
{
dc->th = NULL;
}
GNUNET_CLIENT_disconnect (dc->client, GNUNET_NO);
+ dc->in_receive = GNUNET_NO;
dc->client = NULL;
GNUNET_FS_free_download_request_ (dc->top_request);
dc->top_request = NULL;
dc);
GNUNET_assert (dc->th != NULL);
}
+ if (GNUNET_NO == dc->in_receive)
+ {
+ dc->in_receive = GNUNET_YES;
+ GNUNET_CLIENT_receive (dc->client,
+ &receive_results,
+ dc,
+ GNUNET_TIME_UNIT_FOREVER_REL);
+ }
return msize;
}
dc);
GNUNET_assert (dc->th != NULL);
}
- GNUNET_CLIENT_receive (client,
- &receive_results,
- dc,
- GNUNET_TIME_UNIT_FOREVER_REL);
}
struct GNUNET_FS_DownloadContext *dc = cls;
struct DownloadRequest *dr = entry;
+ dr->next = NULL;
+ dr->prev = NULL;
GNUNET_CONTAINER_DLL_insert (dc->pending_head,
dc->pending_tail,
dr);
&retry_entry,
dc);
GNUNET_CLIENT_disconnect (dc->client, GNUNET_NO);
+ dc->in_receive = GNUNET_NO;
dc->client = NULL;
}
#if DEBUG_DOWNLOAD
GNUNET_assert (dc->client == NULL);
GNUNET_assert (dc->th == NULL);
dc->client = client;
- GNUNET_CLIENT_receive (client,
- &receive_results,
- dc,
- GNUNET_TIME_UNIT_FOREVER_REL);
pi.status = GNUNET_FS_STATUS_DOWNLOAD_ACTIVE;
GNUNET_FS_download_make_status_ (&pi, dc);
+ dc->pending_head = NULL;
+ dc->pending_tail = NULL;
GNUNET_CONTAINER_multihashmap_iterate (dc->active,
&retry_entry,
dc);
if (NULL != dc->client)
{
GNUNET_CLIENT_disconnect (dc->client, GNUNET_NO);
+ dc->in_receive = GNUNET_NO;
dc->client = NULL;
}
+ dc->pending_head = NULL;
+ dc->pending_tail = NULL;
pi.status = GNUNET_FS_STATUS_DOWNLOAD_INACTIVE;
GNUNET_FS_download_make_status_ (&pi, dc);
}
* @param file_start_offset desired starting offset for the download
* in the original file; requesting tree should not contain
* DBLOCKs prior to the file_start_offset
- * @param file_length desired number of bytes the user wanted to access
+ * @param desired_length desired number of bytes the user wanted to access
* (from file_start_offset). Resulting tree should not contain
* DBLOCKs after file_start_offset + file_length.
* @return download request tree for the given range of DBLOCKs at
/**
* Task requesting the next block from the tree encoder.
*
+ * @param cls the 'struct GNUJNET_FS_DownloadContext' we're processing
* @param tc task context
*/
static void
/* no bytes required! */
if (dc->filename != NULL)
{
- fh = GNUNET_DISK_file_open (dc->filename != NULL
- ? dc->filename
- : dc->temp_filename,
+ fh = GNUNET_DISK_file_open (dc->filename,
GNUNET_DISK_OPEN_READWRITE |
GNUNET_DISK_OPEN_CREATE |
( (0 == GNUNET_FS_uri_chk_get_file_size (dc->uri))
if (dc->rfh != NULL)
{
/* first, try top-down */
+#if DEBUG_DOWNLOAD
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Trying top-down reconstruction for `%s'\n",
+ dc->filename);
+#endif
try_top_down_reconstruction (dc, dc->top_request);
switch (dc->top_request->state)
{
break; /* normal, some blocks already down */
case BRS_DOWNLOAD_UP:
/* already done entirely, party! */
- dc->completed = dc->length;
- GNUNET_FS_download_sync_ (dc);
- pi.status = GNUNET_FS_STATUS_DOWNLOAD_PROGRESS;
- /* slightly ugly: no data provided to callee; maybe mmap the
- file instead? Or is 'data' pure convenience!? */
- pi.value.download.specifics.progress.data = NULL;
- pi.value.download.specifics.progress.offset = dc->offset;
- pi.value.download.specifics.progress.data_len = dc->length;
- pi.value.download.specifics.progress.depth = 0;
- GNUNET_FS_download_make_status_ (&pi, dc);
if (dc->rfh != NULL)
{
/* avoid hanging on to file handle longer than
GNUNET_DISK_file_close (dc->rfh);
dc->rfh = NULL;
}
- check_completed (dc);
return;
case BRS_ERROR:
GNUNET_asprintf (&dc->emsg,
if (dc->rfh != NULL)
{
/* finally, try bottom-up */
+#if DEBUG_DOWNLOAD
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Trying bottom-up reconstruction of file `%s'\n",
+ dc->filename);
+#endif
dc->te = GNUNET_FS_tree_encoder_create (dc->h,
dc->old_file_size,
dc,