allow file hashing cancellation -- and make use of it
authorChristian Grothoff <christian@grothoff.org>
Thu, 6 May 2010 19:59:59 +0000 (19:59 +0000)
committerChristian Grothoff <christian@grothoff.org>
Thu, 6 May 2010 19:59:59 +0000 (19:59 +0000)
src/fs/fs.c
src/fs/fs.h
src/fs/fs_unindex.c
src/fs/gnunet-service-fs_indexing.c
src/include/gnunet_crypto_lib.h
src/transport/plugin_transport_http.c
src/util/crypto_hash.c
src/util/test_crypto_hash.c

index 31c8eee49cd78c626f75f321a965316e59280d18..1968a8453d928089dd19cfd0231a396cf3867c87 100644 (file)
@@ -2058,12 +2058,12 @@ deserialize_unindex_file (void *cls,
   switch (uc->state)
     {
     case UNINDEX_STATE_HASHING:
-      GNUNET_CRYPTO_hash_file (uc->h->sched,
-                              GNUNET_SCHEDULER_PRIORITY_IDLE,
-                              uc->filename,
-                              HASHING_BLOCKSIZE,
-                              &GNUNET_FS_unindex_process_hash_,
-                              uc);
+      uc->fhc = GNUNET_CRYPTO_hash_file (uc->h->sched,
+                                        GNUNET_SCHEDULER_PRIORITY_IDLE,
+                                        uc->filename,
+                                        HASHING_BLOCKSIZE,
+                                        &GNUNET_FS_unindex_process_hash_,
+                                        uc);
       break;
     case UNINDEX_STATE_FS_NOTIFY:
       uc->state = UNINDEX_STATE_HASHING;
index d8e9973243a37be722a5d6ed1b01696fc3fae860..bca8fc6916ad4db9f76170aa848d58c90f7cba26 100644 (file)
@@ -1407,6 +1407,11 @@ struct GNUNET_FS_UnindexContext
    */
   char *emsg;
 
+  /**
+   * Context for hashing of the file.
+   */
+  struct GNUNET_CRYPTO_FileHashContext *fhc;
+
   /**
    * Overall size of the file.
    */ 
index 5989fd2c0c89d568cc30c4d2bf3d23c7782ef492..db054060779851ac411a97eb8ef5199153d46ce0 100644 (file)
@@ -365,6 +365,7 @@ GNUNET_FS_unindex_process_hash_ (void *cls,
   struct GNUNET_FS_UnindexContext *uc = cls;
   struct UnindexMessage req;
 
+  uc->fhc = NULL;
   if (uc->state != UNINDEX_STATE_HASHING) 
     {
       GNUNET_FS_unindex_stop (uc);
@@ -410,6 +411,11 @@ GNUNET_FS_unindex_signal_suspend_ (void *cls)
   struct GNUNET_FS_UnindexContext *uc = cls;
   struct GNUNET_FS_ProgressInfo pi;
 
+  if (uc->fhc != NULL)
+    {
+      GNUNET_CRYPTO_hash_file_cancel (uc->fhc);
+      uc->fhc = NULL;
+    }
   GNUNET_FS_end_top (uc->h, uc->top);
   pi.status = GNUNET_FS_STATUS_UNINDEX_SUSPEND;
   GNUNET_FS_unindex_make_status_ (&pi, uc, 
@@ -454,13 +460,12 @@ GNUNET_FS_unindex_start (struct GNUNET_FS_Handle *h,
   pi.status = GNUNET_FS_STATUS_UNINDEX_START;
   pi.value.unindex.eta = GNUNET_TIME_UNIT_FOREVER_REL;
   GNUNET_FS_unindex_make_status_ (&pi, ret, 0);
-  /* FIXME: must be able to abort hashing here! */
-  GNUNET_CRYPTO_hash_file (h->sched,
-                          GNUNET_SCHEDULER_PRIORITY_IDLE,
-                          filename,
-                          HASHING_BLOCKSIZE,
-                          &GNUNET_FS_unindex_process_hash_,
-                          ret);
+  ret->fhc = GNUNET_CRYPTO_hash_file (h->sched,
+                                     GNUNET_SCHEDULER_PRIORITY_IDLE,
+                                     filename,
+                                     HASHING_BLOCKSIZE,
+                                     &GNUNET_FS_unindex_process_hash_,
+                                     ret);
   ret->top = GNUNET_FS_make_top (h,
                                 &GNUNET_FS_unindex_signal_suspend_,
                                 ret);
@@ -478,7 +483,11 @@ GNUNET_FS_unindex_stop (struct GNUNET_FS_UnindexContext *uc)
 {  
   struct GNUNET_FS_ProgressInfo pi;
   
-  /* FIXME: stop hashing (if still ongoing) */
+  if (uc->fhc != NULL)
+    {
+      GNUNET_CRYPTO_hash_file_cancel (uc->fhc);
+      uc->fhc = NULL;
+    }
   /* FIXME: disconnect uc->client (if still connected) */
   /* FIXME: disconnect from datastore (if still connected) */
   /* FIXME: other termination operations? */
index a5ac0dda3d9b1079f63cb0a19793423c22c0e666..f8593ffd45e846ed1a9c632b27a56e280a1bc359 100644 (file)
  * @file fs/gnunet-service-fs_indexing.c
  * @brief program that provides indexing functions of the file-sharing service
  * @author Christian Grothoff
+ *
+ * TODO:
+ * - consider doing GNUNET_CRYPTO_hash_file_cancel on active indexing
+ *   jobs during shutdown (currently, shutdown will only happen after
+ *   all of those are done, not sure if this is good or bad)
  */
 #include "platform.h"
 #include <float.h>
@@ -60,6 +65,11 @@ struct IndexInfo
    * NULL if we've done this already.
    */
   struct GNUNET_SERVER_TransmitContext *tc;
+
+  /**
+   * Context for hashing of the file.
+   */
+  struct GNUNET_CRYPTO_FileHashContext *fhc;
   
   /**
    * Hash of the contents of the file.
@@ -282,7 +292,8 @@ hash_for_index_val (void *cls,
                    res)
 {
   struct IndexInfo *ii = cls;
-  
+
+  ii->fhc = NULL;
   if ( (res == NULL) ||
        (0 != memcmp (res,
                     &ii->file_id,
@@ -375,12 +386,14 @@ GNUNET_FS_handle_index_start (void *cls,
              (unsigned int) mydev);
 #endif
   /* slow validation, need to hash full file (again) */
-  GNUNET_CRYPTO_hash_file (sched,
-                          GNUNET_SCHEDULER_PRIORITY_IDLE,
-                          fn,
-                          HASHING_BLOCKSIZE,
-                          &hash_for_index_val,
-                          ii);
+  ii->fhc = GNUNET_CRYPTO_hash_file (sched,
+                                    GNUNET_SCHEDULER_PRIORITY_IDLE,
+                                    fn,
+                                    HASHING_BLOCKSIZE,
+                                    &hash_for_index_val,
+                                    ii);
+  if (ii->fhc == NULL)    
+    hash_for_index_val (ii, NULL);    
   GNUNET_free (fn);
 }
 
index 1dc9cb1aae92d660cd661aa362f7de85375dc369..e1eb0f28d1e7d7364f47473e41c9f6e722da7c20 100644 (file)
@@ -365,6 +365,11 @@ typedef void (*GNUNET_CRYPTO_HashCompletedCallback) (void *cls,
                                                      res);
 
 
+/**
+ * Handle to file hashing operation.
+ */
+struct GNUNET_CRYPTO_FileHashContext;
+
 /**
  * Compute the hash of an entire file.
  *
@@ -374,13 +379,24 @@ typedef void (*GNUNET_CRYPTO_HashCompletedCallback) (void *cls,
  * @param blocksize number of bytes to process in one task
  * @param callback function to call upon completion
  * @param callback_cls closure for callback
+ * @return NULL on (immediate) errror
+ */
+struct GNUNET_CRYPTO_FileHashContext *
+GNUNET_CRYPTO_hash_file (struct GNUNET_SCHEDULER_Handle *sched,
+                        enum GNUNET_SCHEDULER_Priority priority,
+                        const char *filename,
+                        size_t blocksize,
+                        GNUNET_CRYPTO_HashCompletedCallback callback,
+                        void *callback_cls);
+
+
+/**
+ * Cancel a file hashing operation.
+ *
+ * @param fhc operation to cancel (callback must not yet have been invoked)
  */
-void GNUNET_CRYPTO_hash_file (struct GNUNET_SCHEDULER_Handle *sched,
-                              enum GNUNET_SCHEDULER_Priority priority,
-                              const char *filename,
-                              size_t blocksize,
-                              GNUNET_CRYPTO_HashCompletedCallback callback,
-                              void *callback_cls);
+void
+GNUNET_CRYPTO_hash_file_cancel (struct GNUNET_CRYPTO_FileHashContext *fhc);
 
 
 /**
index da3d03a1909ca2b9140bd061727c9231d0f3223f..c0de034ac1fd3efe642b726b68e568601d6d3c9f 100644 (file)
@@ -181,12 +181,14 @@ static char * get_url( const struct GNUNET_PeerIdentity * target)
   return strdup("http://localhost:12389");
 }
 
+#if 0
 static size_t curl_read_function( void *ptr, size_t size, size_t nmemb, void *stream)
 {
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"curl read function\n");
   // strcpy ("Testmessa")
   return 0;
 }
+#endif
 
 /**
  * Task that is run when we are ready to receive more data from the hostlist
index dcee545f79e811b20ff2fc1f0272a8d48e25e9c9..60104b604263a2b0a6b95b20618e66cd379b9a6d 100644 (file)
@@ -372,7 +372,7 @@ GNUNET_CRYPTO_hash (const void *block, size_t size, GNUNET_HashCode * ret)
 /**
  * Context used when hashing a file.
  */
-struct FileHashContext
+struct GNUNET_CRYPTO_FileHashContext
 {
 
   /**
@@ -396,14 +396,19 @@ struct FileHashContext
   char *filename;
 
   /**
-   * Cummulated hash.
+   * File descriptor.
    */
-  struct sha512_ctx hctx;
+  struct GNUNET_DISK_FileHandle *fh;
 
   /**
-   * Blocksize.
+   * Our scheduler.
    */
-  size_t bsize;
+  struct GNUNET_SCHEDULER_Handle *sched;
+
+  /**
+   * Cummulated hash.
+   */
+  struct sha512_ctx hctx;
 
   /**
    * Size of the file.
@@ -416,9 +421,14 @@ struct FileHashContext
   uint64_t offset;
 
   /**
-   * File descriptor.
+   * Current task for hashing.
    */
-  struct GNUNET_DISK_FileHandle *fh;
+  GNUNET_SCHEDULER_TaskIdentifier task;
+
+  /**
+   * Blocksize.
+   */
+  size_t bsize;
 
 };
 
@@ -428,7 +438,8 @@ struct FileHashContext
  * and free associated resources.
  */
 static void
-file_hash_finish (struct FileHashContext *fhc, const GNUNET_HashCode * res)
+file_hash_finish (struct GNUNET_CRYPTO_FileHashContext *fhc, 
+                 const GNUNET_HashCode * res)
 {
   fhc->callback (fhc->callback_cls, res);
   GNUNET_free (fhc->filename);
@@ -447,10 +458,11 @@ file_hash_finish (struct FileHashContext *fhc, const GNUNET_HashCode * res)
 static void
 file_hash_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
-  struct FileHashContext *fhc = cls;
+  struct GNUNET_CRYPTO_FileHashContext *fhc = cls;
   GNUNET_HashCode res;
   size_t delta;
 
+  fhc->task = GNUNET_SCHEDULER_NO_TASK;
   GNUNET_assert (fhc->offset < fhc->fsize);
   delta = fhc->bsize;
   if (fhc->fsize - fhc->offset < delta)
@@ -470,8 +482,10 @@ file_hash_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
       file_hash_finish (fhc, &res);
       return;
     }
-  GNUNET_SCHEDULER_add_after (tc->sched,
-                              GNUNET_SCHEDULER_NO_TASK, &file_hash_task, fhc);
+  fhc->task 
+    = GNUNET_SCHEDULER_add_after (tc->sched,
+                                 GNUNET_SCHEDULER_NO_TASK, 
+                                 &file_hash_task, fhc);
 }
 
 
@@ -484,8 +498,9 @@ file_hash_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  * @param blocksize number of bytes to process in one task
  * @param callback function to call upon completion
  * @param callback_cls closure for callback
+ * @return NULL on (immediate) errror
  */
-void
+struct GNUNET_CRYPTO_FileHashContext *
 GNUNET_CRYPTO_hash_file (struct GNUNET_SCHEDULER_Handle *sched,
                          enum GNUNET_SCHEDULER_Priority priority,
                          const char *filename,
@@ -493,12 +508,13 @@ GNUNET_CRYPTO_hash_file (struct GNUNET_SCHEDULER_Handle *sched,
                          GNUNET_CRYPTO_HashCompletedCallback callback,
                          void *callback_cls)
 {
-  struct FileHashContext *fhc;
+  struct GNUNET_CRYPTO_FileHashContext *fhc;
 
   GNUNET_assert (blocksize > 0);
-  fhc = GNUNET_malloc (sizeof (struct FileHashContext) + blocksize);
+  fhc = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_FileHashContext) + blocksize);
   fhc->callback = callback;
   fhc->callback_cls = callback_cls;
+  fhc->sched = sched;
   fhc->buffer = (unsigned char *) &fhc[1];
   fhc->filename = GNUNET_strdup (filename);
   fhc->fh = NULL;
@@ -506,21 +522,43 @@ GNUNET_CRYPTO_hash_file (struct GNUNET_SCHEDULER_Handle *sched,
   fhc->bsize = blocksize;
   if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fhc->fsize, GNUNET_NO))
     {
-      file_hash_finish (fhc, NULL);
-      return;
+      GNUNET_free (fhc->filename);
+      GNUNET_free (fhc);
+      return NULL;
     }
   fhc->fh = GNUNET_DISK_file_open (filename,
                                    GNUNET_DISK_OPEN_READ,
                                    GNUNET_DISK_PERM_NONE);
   if (!fhc->fh)
     {
-      file_hash_finish (fhc, NULL);
-      return;
+      GNUNET_free (fhc->filename);
+      GNUNET_free (fhc);
+      return NULL;
     }
-  GNUNET_SCHEDULER_add_with_priority (sched, priority, &file_hash_task, fhc);
+  fhc->task 
+    = GNUNET_SCHEDULER_add_with_priority (sched, priority, 
+                                         &file_hash_task, fhc);
+  return fhc;
+}
+
+
+/**
+ * Cancel a file hashing operation.
+ *
+ * @param fhc operation to cancel (callback must not yet have been invoked)
+ */
+void
+GNUNET_CRYPTO_hash_file_cancel (struct GNUNET_CRYPTO_FileHashContext *fhc)
+{
+  GNUNET_SCHEDULER_cancel (fhc->sched,
+                          fhc->task);
+  GNUNET_free (fhc->filename);
+  GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fhc->fh));
+  GNUNET_free (fhc);
 }
 
 
+
 /* ***************** binary-ASCII encoding *************** */
 
 /**
index b650355c09ce67f2b99ab19d6615928fd8a9f242..f793e3342319aa7eedc071d2dd9ed01fbe31d174 100644 (file)
@@ -122,9 +122,11 @@ finished_task (void *cls, const GNUNET_HashCode * res)
 static void
 file_hasher (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
-  GNUNET_CRYPTO_hash_file (tc->sched,
-                           GNUNET_SCHEDULER_PRIORITY_DEFAULT,
-                           FILENAME, 1024, &finished_task, cls);
+  GNUNET_assert (NULL !=
+                GNUNET_CRYPTO_hash_file (tc->sched,
+                                         GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+                                         FILENAME, 1024,
+                                         &finished_task, cls));
 }