arg
[oweals/gnunet.git] / src / fs / fs_download.c
index 126868e7beb056a8c65ed73feed477e589aad914..1565f9a3d5e2a6a5b97a7e57768fdb8286001956 100644 (file)
@@ -97,38 +97,6 @@ compute_disk_offset (uint64_t fsize,
 }
 
 
-/**
- * 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.
@@ -463,7 +431,7 @@ check_completed (struct GNUNET_FS_DownloadContext *dc)
  * 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
@@ -603,8 +571,9 @@ try_match_block (struct GNUNET_FS_DownloadContext *dc,
       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);
@@ -787,10 +756,12 @@ try_top_down_reconstruction (struct GNUNET_FS_DownloadContext *dc,
       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 */
     } 
@@ -846,16 +817,21 @@ 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),
@@ -990,6 +966,7 @@ trigger_recursive_download (void *cls,
                           DIR_SEPARATOR_STR,
                           sfn);
        }
+      GNUNET_free (sfn);
       GNUNET_free (dn);
     }
   if ( (full_name != NULL) &&
@@ -1271,9 +1248,6 @@ process_result_with_request (void *cls,
   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)
        {
@@ -1324,6 +1298,7 @@ process_result_with_request (void *cls,
       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;
@@ -1485,6 +1460,14 @@ transmit_download_request (void *cls,
                                                    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;
 }
 
@@ -1524,10 +1507,6 @@ do_reconnect (void *cls,
                                                    dc);
       GNUNET_assert (dc->th != NULL);
     }
-  GNUNET_CLIENT_receive (client,
-                        &receive_results,
-                        dc,
-                        GNUNET_TIME_UNIT_FOREVER_REL);
 }
 
 
@@ -1547,6 +1526,8 @@ retry_entry (void *cls,
   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);
@@ -1584,6 +1565,7 @@ try_reconnect (struct GNUNET_FS_DownloadContext *dc)
                                             &retry_entry,
                                             dc);
       GNUNET_CLIENT_disconnect (dc->client, GNUNET_NO);
+      dc->in_receive = GNUNET_NO;
       dc->client = NULL;
     }
 #if DEBUG_DOWNLOAD
@@ -1618,12 +1600,10 @@ activate_fs_download (void *cls,
   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);
@@ -1667,8 +1647,11 @@ deactivate_fs_download (void *cls)
   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);
 }
@@ -1965,9 +1948,7 @@ GNUNET_FS_download_start_task_ (void *cls,
       /* 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))