gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r925 - in GNUnet: . contrib src/applications/fs/ecrs src/ap


From: grothoff
Subject: [GNUnet-SVN] r925 - in GNUnet: . contrib src/applications/fs/ecrs src/applications/fs/fsui src/applications/fs/tools src/include
Date: Tue, 14 Jun 2005 09:58:27 -0700 (PDT)

Author: grothoff
Date: 2005-06-14 09:58:05 -0700 (Tue, 14 Jun 2005)
New Revision: 925

Modified:
   GNUnet/contrib/gnunet.root
   GNUnet/src/applications/fs/ecrs/upload.c
   GNUnet/src/applications/fs/fsui/download.c
   GNUnet/src/applications/fs/fsui/fsui.c
   GNUnet/src/applications/fs/fsui/fsui.h
   GNUnet/src/applications/fs/fsui/search.c
   GNUnet/src/applications/fs/fsui/unindex.c
   GNUnet/src/applications/fs/fsui/upload.c
   GNUnet/src/applications/fs/tools/gnunet-download.c
   GNUnet/src/applications/fs/tools/gnunet-insert.c
   GNUnet/src/applications/fs/tools/gnunet-search.c
   GNUnet/src/applications/fs/tools/gnunet-unindex.c
   GNUnet/src/include/gnunet_fsui_lib.h
   GNUnet/todo
Log:
partial bugfixes

Modified: GNUnet/contrib/gnunet.root
===================================================================
--- GNUnet/contrib/gnunet.root  2005-06-13 20:56:27 UTC (rev 924)
+++ GNUnet/contrib/gnunet.root  2005-06-14 16:58:05 UTC (rev 925)
@@ -562,6 +562,14 @@
 # Default is $GNUNETD_HOME/data/shared/
 INDEX-DIRECTORY = $GNUNETD_HOME/data/shared/
 
+# How many (parallel) threads should a given gnunet-download (or
+# gnunet-gtk) process run?  (this limits the amount of parallelism
+# used in the FSUI library).  Smaller values reduce memory and CPU
+# requirements.  Very large values will not be useful since even if
+# that much parallelism is theoretically possible, the local node may
+# not be able to route that many parallel requests anyway.  
+# Default: 32
+POOL = 32
 
 #######################################
 # MySQL specific options.

Modified: GNUnet/src/applications/fs/ecrs/upload.c
===================================================================
--- GNUnet/src/applications/fs/ecrs/upload.c    2005-06-13 20:56:27 UTC (rev 
924)
+++ GNUnet/src/applications/fs/ecrs/upload.c    2005-06-14 16:58:05 UTC (rev 
925)
@@ -204,11 +204,12 @@
 
        switch(FS_initIndex(sock, &fileId, filename)) {
                case SYSERR:
-                       LOG(LOG_ERROR, "'%s' failed.\n", _("Initialization"));
+                       LOG(LOG_ERROR, _("Initialization for indexing file '%s' 
failed.\n"), filename);
        return SYSERR;
                case NO:
-                       LOG(LOG_ERROR, "Indexing %s failed. Check file 
permissions and consult "
-                               "your GNUnet server's logs.\n", filename);
+                       LOG(LOG_ERROR, 
+                           _("Indexing file '%s' failed. Check file 
permissions and consult "
+                               "your GNUnet server's logs.\n"), filename);
        return SYSERR;                  
        }
 

Modified: GNUnet/src/applications/fs/fsui/download.c
===================================================================
--- GNUnet/src/applications/fs/fsui/download.c  2005-06-13 20:56:27 UTC (rev 
924)
+++ GNUnet/src/applications/fs/fsui/download.c  2005-06-14 16:58:05 UTC (rev 
925)
@@ -23,13 +23,6 @@
  * @brief download functions
  * @author Krista Bennett
  * @author Christian Grothoff
- *
- * BIG FIXME: the download code still has some very serious issues in
- * particular with recursive downloads (and the tree model of them).
- * This may result in segfaults on exit and other bad side-effects.
- *
- * Also, it spawns far, far too many concurrent threads (lots to be
- * fixed, probably including a re-design to clean things up).
  */
 
 #include "platform.h"
@@ -37,6 +30,7 @@
 #include "gnunet_fsui_lib.h"
 #include "fsui.h"
 
+
 /**
  * Start to download a file.
  *
@@ -63,12 +57,12 @@
     if (ECRS_equalsUri(parent->completedDownloads[i],
                       fi->uri))
       return OK; /* already complete! */
-  pos = parent->subDownloads;
+  pos = parent->child;
   while (pos != NULL) {
     if (ECRS_equalsUri(pos->uri,
                       fi->uri))
       return OK; /* already downloading */
-    pos = pos->subDownloadsNext;
+    pos = pos->next;
   }
   filename = ECRS_getFromMetaData(fi->meta,
                                  EXTRACTOR_FILENAME);
@@ -113,11 +107,12 @@
   FSUI_DownloadList * root;
 
   root = dl;
-  while (root->parent != NULL)
+  while ( (root->parent != NULL) &&
+         (root->parent != &dl->ctx->activeDownloads) )
     root = root->parent;
 
   dl->completed = completedBytes;
-  event.type = download_progress;
+  event.type = FSUI_download_progress;
   event.data.DownloadProgress.total = totalBytes;
   event.data.DownloadProgress.completed = completedBytes;
   event.data.DownloadProgress.last_offset = lastBlockOffset;
@@ -130,6 +125,7 @@
   event.data.DownloadProgress.is_recursive = dl->is_recursive;
   event.data.DownloadProgress.main_filename = root->filename;
   event.data.DownloadProgress.main_uri = root->uri;
+  event.data.DownloadProgress.pos = dl;
   dl->ctx->ecb(dl->ctx->ecbClosure,
               &event);
   if ( (lastBlockOffset == 0) &&
@@ -175,19 +171,15 @@
 void * downloadThread(FSUI_DownloadList * dl) {
   int ret;
   FSUI_Event event;
-  unsigned long long totalBytes;
-  FSUI_DownloadList * prev;
-  FSUI_DownloadList * pos;
   struct ECRS_MetaData * md;
   FSUI_DownloadList * root;
+  unsigned long long totalBytes;
 
-  totalBytes = ECRS_fileSize(dl->uri);
+  GNUNET_ASSERT(dl->ctx != NULL);
   root = dl;
-  while (root->parent != NULL) {    
+  while ( (root->parent != NULL) &&
+         (root->parent != &dl->ctx->activeDownloads) ) {
     root = root->parent;
-    if (root != NULL) {
-      root->total += totalBytes;
-    }
   }
 
   GNUNET_ASSERT(dl->filename != NULL);
@@ -198,24 +190,11 @@
                          dl,
                          (ECRS_TestTerminate) &testTerminate,
                          dl);
-  if (ret != OK) {
-    event.type = download_error;
-    event.data.message = _("Download aborted.");
-  } else {
-    event.type = download_complete;
-    event.data.DownloadProgress.total = root->total;
-    event.data.DownloadProgress.completed = root->completed;
-    event.data.DownloadProgress.last_offset = 0;
-    event.data.DownloadProgress.eta = cronTime(NULL);
-    event.data.DownloadProgress.last_block = NULL;
-    event.data.DownloadProgress.last_size = 0;
-    event.data.DownloadProgress.filename = dl->filename;
-    event.data.DownloadProgress.uri = dl->uri;
-    event.data.DownloadProgress.start_time = dl->startTime;
-    event.data.DownloadProgress.is_recursive = dl->is_recursive;
-    event.data.DownloadProgress.main_filename = root->filename;
-    event.data.DownloadProgress.main_uri = root->uri;
-  }
+  /* MAYBE FIXME: ___ ret == OK possible without download complete or at 
+     least without downloadProgressCallback called with complete?? __ 
+     (possibly only with resumed download???) */
+  if (ret == OK)
+    dl->finished = YES;  
   if ( (ret == OK) &&
        (dl->is_recursive) &&
        (dl->is_directory) ) {
@@ -224,16 +203,18 @@
 
 #ifdef O_LARGEFILE
     fd = fileopen(dl->filename,
-             O_LARGEFILE | O_RDONLY);
+                 O_LARGEFILE | O_RDONLY);
 #else
     fd = fileopen(dl->filename,
-             O_RDONLY);
+                 O_RDONLY);
 #endif
     if (fd == -1) {
       LOG_FILE_STRERROR(LOG_ERROR,
                        "OPEN",
                        dl->filename);
     } else {
+      totalBytes = ECRS_fileSize(dl->uri);
+
       dirBlock = MMAP(NULL,
                      totalBytes,
                      PROT_READ,
@@ -253,42 +234,43 @@
       MUNMAP(dirBlock, totalBytes);
       closefile(fd);
     }
-
-    /* wait for recursive downloads (if any) */
-    while ( (dl->subDownloads != NULL) &&
-           (dl->signalTerminate != YES) )
-      gnunet_util_sleep(100);
   }
-  dl->ctx->ecb(dl->ctx->ecbClosure,
-              &event);
-  if (dl->parent != NULL) {
-    /* notify parent that we're done */
-    MUTEX_LOCK(&dl->ctx->lock);
-    GROW(dl->parent->completedDownloads,
-        dl->parent->completedDownloadsCount,
-        dl->parent->completedDownloadsCount+1);
-    dl->parent->completedDownloads[dl->parent->completedDownloadsCount-1]
-      = ECRS_dupUri(dl->uri);
-    prev = NULL;
-    pos = dl->parent->subDownloads;
-    while ( (pos != NULL) &&
-           (pos != dl) ) {
-      prev = pos;
-      pos = pos->subDownloadsNext;
-    }
-    if (pos == NULL) {
-      BREAK();
+  if (ret != OK) {
+    if (dl->signalTerminate == YES) {
+      event.type = FSUI_download_aborted;
+      event.data.DownloadError.message = _("Download aborted.");
     } else {
-      if (prev != NULL)
-       prev->subDownloadsNext 
-         = pos->subDownloadsNext;
-      else
-       dl->parent->subDownloads
-         = pos->subDownloadsNext;
+      event.type = FSUI_download_error;
+      event.data.DownloadError.message = _("ECRS download failed (see logs).");
     }
-    MUTEX_UNLOCK(&dl->ctx->lock);
+    event.data.DownloadError.pos = dl;
+    dl->ctx->ecb(dl->ctx->ecbClosure,
+                &event);
+    dl->signalTerminate = YES;
+  } else {
+    dl->signalTerminate = YES;
+    while ( (dl != NULL) &&
+           (dl->ctx != NULL) &&
+           (dl != &dl->ctx->activeDownloads) ) {
+      event.type = FSUI_download_complete;
+      event.data.DownloadProgress.total = root->total;
+      event.data.DownloadProgress.completed = root->completed;
+      event.data.DownloadProgress.last_offset = 0;
+      event.data.DownloadProgress.eta = cronTime(NULL);
+      event.data.DownloadProgress.last_block = NULL;
+      event.data.DownloadProgress.last_size = 0;
+      event.data.DownloadProgress.filename = dl->filename;
+      event.data.DownloadProgress.uri = dl->uri;
+      event.data.DownloadProgress.start_time = dl->startTime;
+      event.data.DownloadProgress.is_recursive = dl->is_recursive;
+      event.data.DownloadProgress.main_filename = root->filename;
+      event.data.DownloadProgress.main_uri = root->uri;
+      event.data.DownloadProgress.pos = dl;
+      dl->ctx->ecb(dl->ctx->ecbClosure,
+                  &event);
+      dl = dl->parent;
+    }
   }
-  dl->signalTerminate = YES;
   return NULL;
 }
 
@@ -306,7 +288,10 @@
                         int is_recursive,
                         FSUI_DownloadList * parent) {
   FSUI_DownloadList * dl;
+  FSUI_DownloadList * root;
+  unsigned long long totalBytes;
 
+  GNUNET_ASSERT(ctx != NULL);
   if (! (ECRS_isFileUri(uri) ||
         ECRS_isLocationUri(uri)) ) {
     BREAK(); /* wrong type of URI! */
@@ -316,8 +301,8 @@
   dl = MALLOC(sizeof(FSUI_DownloadList));
   memset(dl, 0, sizeof(FSUI_DownloadList));
   cronTime(&dl->startTime);
-  dl->signalTerminate = NO;
-  dl->threadStarted = NO;
+  dl->signalTerminate = SYSERR;
+  dl->finished = NO;
   dl->is_recursive = is_recursive;
   dl->parent = parent;
   dl->is_directory = SYSERR; /* don't know */
@@ -326,27 +311,16 @@
   dl->filename = STRDUP(filename);
   dl->uri = ECRS_dupUri(uri);
   dl->total = ECRS_fileSize(uri);
-  MUTEX_LOCK(&ctx->lock);
-  if (0 != PTHREAD_CREATE(&dl->handle,
-                         (PThreadMain) &downloadThread,
-                         dl,
-                         128 * 1024)) {
-    FREE(dl->filename);
-    ECRS_freeUri(dl->uri);
-    FREE(dl);
-    MUTEX_UNLOCK(&ctx->lock);
-    return SYSERR;
+  dl->next = parent->child;
+  parent->child = dl;
+
+  totalBytes = ECRS_fileSize(uri);
+  root = dl;
+  while ( (root->parent != NULL) &&
+         (root->parent != &dl->ctx->activeDownloads) ) {
+    root = root->parent;
+    root->total += totalBytes;
   }
-  dl->threadStarted = YES;
-  if (parent != NULL) {
-    /* add to pending downloads of parent! */
-    dl->subDownloadsNext = parent->subDownloads;
-    parent->subDownloads = dl;
-  }
-  dl->next = ctx->activeDownloads;
-  ctx->activeDownloads = dl;
-  MUTEX_UNLOCK(&ctx->lock);
-  cleanupFSUIThreadList(ctx);
   return OK;
 }
 
@@ -361,16 +335,127 @@
                       unsigned int anonymityLevel,                     
                       const struct ECRS_URI * uri,
                       const char * filename) {
+  int ret;
+
   GNUNET_ASSERT(filename != NULL);
-  return startDownload(ctx,
-                      anonymityLevel,
-                      uri,
-                      filename,
-                      NO,
-                      NULL);
+  GNUNET_ASSERT(ctx != NULL);
+  MUTEX_LOCK(&ctx->lock);
+  ret = startDownload(ctx,
+                     anonymityLevel,
+                     uri,
+                     filename,
+                     NO,
+                     &ctx->activeDownloads);
+  MUTEX_UNLOCK(&ctx->lock);
+  return ret;
 }
 
 /**
+ * Starts or stops download threads in accordance with thread pool
+ * size and active downloads.  Call only while holding FSUI lock (or
+ * during start/stop).
+ *
+ * @return YES if change done that may require re-trying
+ */
+int updateDownloadThread(FSUI_DownloadList * list) {
+  FSUI_DownloadList * dpos;
+  void * unused;
+  int ret;
+
+  if (list == NULL)
+    return NO;
+
+  ret = NO;
+  /* should this one be started? */
+  if ( (list->ctx->threadPoolSize
+       > list->ctx->activeDownloadThreads) &&
+       (list->signalTerminate == SYSERR) &&
+       (list->total > list->completed) &&
+       (list->finished == NO) ) {
+    list->signalTerminate = NO;
+    if (0 == PTHREAD_CREATE(&list->handle,
+                           (PThreadMain)&downloadThread,
+                           list,
+                           32 * 1024)) {
+      list->ctx->activeDownloadThreads++;
+    } else {
+      LOG_STRERROR(LOG_WARNING, "pthread_create");     
+    }
+  }
+  
+  /* should this one be stopped? */
+  if ( (list->ctx->threadPoolSize
+       < list->ctx->activeDownloadThreads) &&
+       (list->signalTerminate == NO) ) {
+    list->signalTerminate = YES;
+    PTHREAD_JOIN(&list->handle,
+                &unused);
+    list->ctx->activeDownloadThreads--;
+    list->signalTerminate = SYSERR;
+    ret = YES;
+  }
+
+  /* has this one "died naturally"? */
+  if (list->signalTerminate == YES) {
+    PTHREAD_JOIN(&list->handle,
+                &unused);
+    list->ctx->activeDownloadThreads--;
+    list->signalTerminate = SYSERR;
+    ret = YES;
+  }
+    
+  dpos = list->child;
+  while (dpos != NULL) {
+    if (YES == updateDownloadThread(dpos))
+      ret = YES;
+    dpos = dpos->next;
+  }
+  return ret;
+}
+
+
+/**
+ * Free the subtree (assumes all threads have already been stopped and
+ * that the FSUI lock is either held or that we are in FSUI stop!).
+ */
+void freeDownloadList(FSUI_DownloadList * list) {
+  FSUI_DownloadList * dpos;
+  int i;
+
+  GNUNET_ASSERT(list->signalTerminate != NO);
+
+  /* first, find our predecessor and
+     unlink us from the tree! */
+  dpos = list->parent;
+  if (dpos != NULL) {
+    if (dpos->child == list)
+      dpos->child = list->next;
+    else {
+      dpos = dpos->child;
+      while ( (dpos != NULL) &&
+             (dpos != list) )
+       dpos = dpos->next;
+      GNUNET_ASSERT(dpos != NULL);
+      dpos->next = list->next;
+    }
+  }
+
+  /* then, free all of our children */
+  while (list->child != NULL)
+    freeDownloadList(list->child);
+
+  /* finally, free this node and its data */
+  ECRS_freeUri(list->uri);
+  FREE(list->filename);
+  for (i=list->completedDownloadsCount-1;i>=0;i--)
+    ECRS_freeUri(list->completedDownloads[i]);
+  GROW(list->completedDownloads,
+       list->completedDownloadsCount,
+       0);
+  FREE(list);
+}
+
+/**
  * Abort a download.
  *
  * @return SYSERR if no such download is pending
@@ -379,18 +464,22 @@
                      const struct ECRS_URI * uri,
                      const char * filename) {
   FSUI_DownloadList * dl;
+  unsigned int backup;
 
   /* FIXME: check that filename matches
      aborted download! */
   GNUNET_ASSERT(filename != NULL);
   MUTEX_LOCK(&ctx->lock);
-  dl = ctx->activeDownloads;
+  dl = ctx->activeDownloads.child;
   while (dl != NULL) {
     if (ECRS_equalsUri(uri,
                       dl->uri)) {
-      dl->signalTerminate = YES;
+      backup = ctx->threadPoolSize;
+      ctx->threadPoolSize = 0;
+      updateDownloadThread(dl);
+      freeDownloadList(dl);
+      ctx->threadPoolSize = backup;
       MUTEX_UNLOCK(&ctx->lock);
-      cleanupFSUIThreadList(ctx);
       return OK;
     }
     dl = dl->next;
@@ -406,17 +495,21 @@
  * events.
  */
 int FSUI_listDownloads(struct FSUI_Context * ctx,
+                      const FSUI_DownloadList * root,
                       FSUI_DownloadIterator iter,
                       void * closure) {
   FSUI_DownloadList * dl;
   int ret;
 
   ret = 0;
-  cleanupFSUIThreadList(ctx);
   MUTEX_LOCK(&ctx->lock);
-  dl = ctx->activeDownloads;
+  if (root == NULL)
+    dl = ctx->activeDownloads.child;
+  else
+    dl = root->child;
   while (dl != NULL) {
     if (OK != iter(closure,
+                  dl,
                   dl->filename,
                   dl->uri,
                   dl->total,
@@ -434,6 +527,19 @@
 }
 
 /**
+ * Get parent of active download. 
+ * @return NULL if there is no parent
+ */
+const FSUI_DownloadList * 
+FSUI_getDownloadParent(const FSUI_DownloadList * child) {
+  if (child->parent ==
+      &child->ctx->activeDownloads)
+    return NULL;
+  else
+    return child->parent;
+}
+
+/**
  * Start to download a file or directory recursively.
  *
  * @return OK on success (at least we started with it),
@@ -443,66 +549,19 @@
                          unsigned int anonymityLevel,                  
                          const struct ECRS_URI * uri,
                          const char * dirname) {
-  GNUNET_ASSERT(dirname != NULL);
-  return startDownload(ctx,
-                      anonymityLevel,
-                      uri,
-                      dirname,
-                      YES,
-                      NULL);
-}
-
-/**
- * Abort a recursive download (internal function).
- *
- * Do NOT call cleanupFSUIThreadList in here -- this
- * function maybe called recursively!
- *
- * @return OK on success, SYSERR if no such download is
- *  pending
- */
-static int stopDownloadAll(struct FSUI_Context * ctx,
-                          const struct ECRS_URI * uri,
-                          const char * dirname) {
-  FSUI_DownloadList * dl;
-  int i;
-
-  GNUNET_ASSERT(dirname != NULL);
-  dl = ctx->activeDownloads;
-  while (dl != NULL) {
-    if ( (0 == strcmp(dirname,
-                     dl->filename)) &&
-        (ECRS_equalsUri(uri,
-                        dl->uri)) ) {
-      dl->signalTerminate = YES;
-      for (i=0;i<dl->completedDownloadsCount;i++)
-       FSUI_stopDownloadAll(ctx,
-                            dl->completedDownloads[i],
-                            dirname);
-      return OK;
-    }
-    dl = dl->next;
-  }
-  return SYSERR;
-}
-
-/**
- * Abort a recursive download.
- *
- * @return OK on success, SYSERR if no such download is
- *  pending
- */
-int FSUI_stopDownloadAll(struct FSUI_Context * ctx,
-                        const struct ECRS_URI * uri,
-                        const char * dirname) {
   int ret;
 
   GNUNET_ASSERT(dirname != NULL);
+  GNUNET_ASSERT(ctx != NULL);
   MUTEX_LOCK(&ctx->lock);
-  ret = stopDownloadAll(ctx, uri, dirname);
+  ret = startDownload(ctx,
+                     anonymityLevel,
+                     uri,
+                     dirname,
+                     YES,
+                     &ctx->activeDownloads);
   MUTEX_UNLOCK(&ctx->lock);
-  cleanupFSUIThreadList(ctx);
   return ret;
 }
-       
+
 /* end of download.c */

Modified: GNUnet/src/applications/fs/fsui/fsui.c
===================================================================
--- GNUnet/src/applications/fs/fsui/fsui.c      2005-06-13 20:56:27 UTC (rev 
924)
+++ GNUnet/src/applications/fs/fsui/fsui.c      2005-06-14 16:58:05 UTC (rev 
925)
@@ -62,20 +62,24 @@
 }
 
 /**
- * (Recursively) read a download list from the 
- * given fd.
+ * (Recursively) read a download list from the given fd.  The returned
+ * pointer is expected to be integrated into the tree either as a next
+ * or child pointer such that the given parent becomes the parent of the
+ * returned node.
  *
  * @return NULL on error AND on read of empty
  *  list (these two cannot be distinguished)
  */
 static FSUI_DownloadList * readDownloadList(int fd,
-                                           FSUI_Context * ctx) {
+                                           FSUI_Context * ctx,
+                                           FSUI_DownloadList * parent) {
   char zaro;
   static FSUI_DownloadList * ret;
   unsigned int big;
   unsigned long long bigl;
   int i;
 
+  GNUNET_ASSERT(ctx != NULL);
   if (1 != READ(fd, &zaro, sizeof(char)))
     return NULL; 
   if (zaro == '\0')
@@ -84,11 +88,12 @@
   ret->ctx = ctx;
 
   ret->signalTerminate 
-    = NO;
+    = SYSERR;
   READINT(ret->is_recursive);
   READINT(ret->is_directory);
   READINT(ret->anonymityLevel);
   READINT(ret->completedDownloadsCount);
+  READINT(ret->finished);
   READINT(big);
   ret->filename = MALLOC(big+1);
   if (big != READ(fd, ret->filename, big))
@@ -113,22 +118,14 @@
   }
   /* FIXME: check if URIs were
      all read successfully! */
-  
+  ret->parent = parent;
+  ret->signalTerminate = SYSERR;
   ret->next = readDownloadList(fd,
-                              ctx);
-  if (ret->next != NULL)
-    ret->next->parent = ret;
-  ret->subDownloads = readDownloadList(fd,
-                                      ctx);
-  ret->subDownloadsNext = readDownloadList(fd,
-                                          ctx);
-
-  /* start download thread! */
-  if (0 != PTHREAD_CREATE(&ret->handle,
-                         (PThreadMain)&downloadThread,
-                         ret,
-                         16 * 1024))
-    DIE_STRERROR("pthread_create");
+                              ctx,
+                              parent);
+  ret->child = readDownloadList(fd,
+                               ctx,
+                               ret);
   return ret;
  ERR:
   FREE(ret);
@@ -182,6 +179,7 @@
   WRITEINT(fd, list->is_directory);
   WRITEINT(fd, list->anonymityLevel);
   WRITEINT(fd, list->completedDownloadsCount);
+  WRITEINT(fd, list->finished);
   WRITEINT(fd, strlen(list->filename));
   WRITE(fd, 
        list->filename,
@@ -196,9 +194,7 @@
   writeDownloadList(fd,
                    list->next);
   writeDownloadList(fd,
-                   list->subDownloads);
-  writeDownloadList(fd,
-                   list->subDownloadsNext);
+                   list->child);
 }
 
 /**
@@ -268,6 +264,19 @@
   writeURI(fd, fi->uri);
 }
 
+static void updateDownloadThreads(void * c) {
+  FSUI_Context * ctx = c;
+  FSUI_DownloadList * dpos;
+
+  MUTEX_LOCK(&ctx->lock);
+  dpos = ctx->activeDownloads.child;
+  while (dpos != NULL) {
+    updateDownloadThread(dpos);
+    dpos = dpos->next;
+  }  
+  MUTEX_UNLOCK(&ctx->lock);
+}
+
 /**
  * Start FSUI manager.  Use the given progress callback to notify the
  * UI about events.  Start processing pending activities that were
@@ -290,6 +299,10 @@
 
   ret = MALLOC(sizeof(FSUI_Context));
   memset(ret, 0, sizeof(FSUI_Context));
+  ret->activeDownloads.signalTerminate 
+    = SYSERR;
+  ret->activeDownloads.ctx
+    = ret;
   gh = getFileName("GNUNET",
                   "GNUNET_HOME",
                   "You must specify a directory for "
@@ -486,9 +499,13 @@
        ret->activeSearches
          = list;
       } 
-      ret->activeDownloads
+      memset(&ret->activeDownloads,
+            0,
+            sizeof(FSUI_DownloadList));
+      ret->activeDownloads.child
        = readDownloadList(fd,
-                          ret);
+                          ret,
+                          &ret->activeDownloads);
       
       /* success, read complete! */
       goto END;
@@ -533,36 +550,18 @@
   MUTEX_CREATE_RECURSIVE(&ret->lock);
   ret->ecb = cb;
   ret->ecbClosure = closure;
-
+  ret->threadPoolSize = getConfigurationInt("FS",
+                                           "POOL");
+  if (ret->threadPoolSize == 0)
+    ret->threadPoolSize = 32;
+  ret->activeDownloadThreads = 0;
+  addCronJob(&updateDownloadThreads,
+            0,
+            2 * cronSECONDS,
+            ret);  
   return ret;
 }
 
-static void freeDownloadList(FSUI_DownloadList * list) {
-  FSUI_DownloadList * dpos;
-  int i;
-  void * unused;
-
-  while (list != NULL) {
-    dpos = list;
-    list = dpos->next;
-    freeDownloadList(dpos->subDownloads);
-    freeDownloadList(dpos->subDownloadsNext);
-    dpos->signalTerminate = YES;
-    if (dpos->threadStarted == YES) {
-      PTHREAD_JOIN(&dpos->handle, &unused);
-      dpos->threadStarted = NO;
-    }
-    ECRS_freeUri(dpos->uri);
-    FREE(dpos->filename);
-    for (i=dpos->completedDownloadsCount-1;i>=0;i--)
-      ECRS_freeUri(dpos->completedDownloads[i]);
-    GROW(dpos->completedDownloads,
-        dpos->completedDownloadsCount,
-        0);
-    FREE(dpos);
-  }
-}
-
 /**
  * Stop all processes under FSUI control (serialize state, continue
  * later if possible).
@@ -570,6 +569,7 @@
 void FSUI_stop(struct FSUI_Context * ctx) {
   FSUI_ThreadList * tpos;
   FSUI_SearchList * spos;
+  FSUI_DownloadList * dpos;
   void * unused;
   int i;
   int fd;
@@ -578,6 +578,22 @@
   LOG(LOG_INFO,
       "FSUI shutdown.  This may take a while.\n");
   FSUI_publishCollectionNow(ctx);
+
+  suspendCron();
+  delCronJob(&updateDownloadThreads,
+            5 * cronSECONDS,
+            ctx);
+  resumeCron();
+  /* first, stop all download threads
+     by reducing the thread pool size to 0 */
+  ctx->threadPoolSize = 0;
+  dpos = ctx->activeDownloads.child;
+  while (dpos != NULL) {
+    updateDownloadThread(dpos);
+    dpos = dpos->next;
+  }
+
+  /* then, wait for all modal threads to complete */
   while (ctx->activeThreads != NULL) {
     tpos = ctx->activeThreads;
     ctx->activeThreads = tpos->next;
@@ -585,6 +601,7 @@
     FREE(tpos);
   }
 
+  /* next, serialize all of the FSUI state */
   if (ctx->ipc != NULL) {
     fd = fileopen(ctx->name, 
                  O_CREAT|O_TRUNC|O_WRONLY, 
@@ -663,6 +680,7 @@
       }
     }
 
+
     ECRS_freeUri(spos->uri);
     for (i=spos->sizeResultsReceived-1;i>=0;i--) {
       ECRS_FileInfo * fi;
@@ -696,12 +714,14 @@
          &big,
          sizeof(unsigned int));
     writeDownloadList(fd,
-                     ctx->activeDownloads);
+                     ctx->activeDownloads.child);
   }
-  freeDownloadList(ctx->activeDownloads);
-  ctx->activeDownloads = NULL;
   if (fd != -1)
     CLOSE(fd);
+
+  /* finally, free all (remaining) FSUI data */
+  while (ctx->activeDownloads.child != NULL)
+    freeDownloadList(ctx->activeDownloads.child);
   if (ctx->ipc != NULL) {
     IPC_SEMAPHORE_UP(ctx->ipc);
     IPC_SEMAPHORE_FREE(ctx->ipc);
@@ -716,16 +736,15 @@
 
 /* *************** internal helper functions *********** */
 
-
+/**
+ * The idea for this function is to clean up
+ * the FSUI structs by freeing up dead entries.
+ */
 void cleanupFSUIThreadList(FSUI_Context * ctx) {
   FSUI_ThreadList * pos;
   FSUI_ThreadList * tmp;
   FSUI_ThreadList * prev;
-  FSUI_DownloadList * dpos;
-  FSUI_DownloadList * dprev;
-  FSUI_DownloadList * dtmp;
   void * unused;
-  int i;
 
   prev = NULL;
   MUTEX_LOCK(&ctx->lock);
@@ -746,41 +765,6 @@
       pos = pos->next;
     }
   }
-
-#if 0
-  /* FIXME: severely broken:
-     - concurrency issue with FSUI_stop,
-     - does not take tree structure into
-       account (activeDownloads is more 
-       than just a linked list!)
-  */
-  dpos = ctx->activeDownloads;
-  dprev = NULL;
-  while (dpos != NULL) {
-    if ( (YES == dpos->signalTerminate) &&
-        (NO == PTHREAD_SELF_TEST(&dpos->handle)) ) {
-      PTHREAD_JOIN(&dpos->handle,
-                  &unused);
-      dtmp = dpos->next;
-      ECRS_freeUri(dpos->uri);
-      FREE(dpos->filename);
-      for (i=0;i<dpos->completedDownloadsCount;i++)
-       ECRS_freeUri(dpos->completedDownloads[i]);
-      GROW(dpos->completedDownloads,
-          dpos->completedDownloadsCount,
-          0);
-      FREE(dpos);
-      if (dprev != NULL)
-       dprev->next = dtmp;
-      else
-       ctx->activeDownloads = dtmp;
-      dpos = dtmp;
-    } else {
-      dprev = dpos;
-      dpos = dpos->next;
-    }
-  }
-#endif
   MUTEX_UNLOCK(&ctx->lock);
 }
 

Modified: GNUnet/src/applications/fs/fsui/fsui.h
===================================================================
--- GNUnet/src/applications/fs/fsui/fsui.h      2005-06-13 20:56:27 UTC (rev 
924)
+++ GNUnet/src/applications/fs/fsui/fsui.h      2005-06-14 16:58:05 UTC (rev 
925)
@@ -34,12 +34,18 @@
  * Linked list of FSUI threads.
  */
 typedef struct FSUI_ThreadList {
+  
+  /**
+   * FSUI threads are kept in a simple
+   * linked list
+   */
   struct FSUI_ThreadList * next;
 
   /**
    * Handle to a thread.
    */
   PTHREAD_T handle;
+
   /**
    * Flag that indicates if it is safe (i.e.
    * non-blocking) to call join on the handle.
@@ -52,15 +58,18 @@
  * Track record for a given result.
  */
 typedef struct {
+
   /**
    * For how many keys (hash of keyword) did we
    * get this result?
    */
   unsigned int matchingKeyCount;
+
   /**
    * What are these keys?
    */
   HashCode512 * matchingKeys;
+
   /**
    * What info do we have about this result?
    */
@@ -71,8 +80,15 @@
  * @brief list of active searches
  */
 typedef struct FSUI_SearchList {
+
+  /**
+   * Searches are kept in a simple linked list.
+   */
   struct FSUI_SearchList * next;
 
+  /**
+   * Context for this search
+   */
   struct FSUI_Context * ctx;
 
   /**
@@ -91,6 +107,9 @@
    */
   struct ECRS_URI * uri;
 
+  /**
+   * Desired anonymity level for this search
+   */
   unsigned int anonymityLevel;
 
   /**
@@ -99,6 +118,9 @@
    */
   unsigned int numberOfURIKeys;
 
+  /**
+   * Size of the resultsReceived array
+   */
   unsigned int sizeResultsReceived;
 
   /**
@@ -138,33 +160,43 @@
    * list of sub-downloads that are currently
    * going on in parallel.
    */
-  struct FSUI_DownloadList * subDownloads;
+  struct FSUI_DownloadList * child;
 
   /**
-   * Next entry in the linked list of subdownloads.
+   * FSUI context for this download.
    */
-  struct FSUI_DownloadList * subDownloadsNext;
+  struct FSUI_Context * ctx;
 
   /**
-   * FSUI context for this download.
+   * Set this to YES to signal the download thread that
+   * termination is desired.  Then join on handle.  
+   * Set to NO if thread is running.  Set to SYSERR
+   * if no thread has been assigned to this download
+   * at the moment.
    */
-  struct FSUI_Context * ctx;
+  int signalTerminate;
 
   /**
-   * Handle to the thread which performs the download.
+   * Is the download of this file finished (not necessarily
+   * transitively for directories, just the directory/file
+   * itself).
    */
+  int finished;
+
+  /**
+   * Currently assigned thread (if any).
+   */
   PTHREAD_T handle;
 
   /**
-   * Set this to YES to signal the download thread that
-   * termination is desired.  Then join on handle.
+   * How many bytes is this download in total
+   * (including files in directory).
    */
-  int signalTerminate;
-
-  int threadStarted;
-
   unsigned long long total;
 
+  /**
+   * How many bytes have been retrieved so far?
+   */
   unsigned long long completed;
 
   /**
@@ -183,7 +215,9 @@
   int is_recursive;
 
   /**
-   * When did the download start?
+   * When did the download start?  Note that if a download is resumed,
+   * this time is set such that the total time is accurate, not the
+   * absolute start time.
    */
   cron_t startTime;
 
@@ -226,8 +260,16 @@
  */
 typedef struct FSUI_Context {
 
+  /**
+   * IPC semaphore used to ensure mutual exclusion
+   * between different processes of the same name
+   * that all use resume.
+   */
   IPC_Semaphore * ipc;
 
+  /**
+   * Name of the tool using FSUI (used for resume).
+   */
   char * name;
 
   /**
@@ -262,20 +304,48 @@
   FSUI_SearchList * activeSearches;
 
   /**
-   * List of active downloads
+   * Root of the tree of downloads.  On shutdown,
+   * FSUI must abort each of these downloads.
    */
-  FSUI_DownloadList * activeDownloads;
+  FSUI_DownloadList activeDownloads;
 
+  /**
+   * Target size of the thread pool for parallel
+   * downloads.
+   */
+  unsigned int threadPoolSize;
+
+  /**
+   * Number of download threads that are
+   * currently active.
+   */
+  unsigned int activeDownloadThreads;
+
 } FSUI_Context;
 
 /**
+ * Starts or stops download threads in accordance with thread pool
+ * size and active downloads.  Call only while holding FSUI lock (or
+ * during start/stop).
+ *
+ * @return YES if change done that may require re-trying
+ */
+int updateDownloadThread(FSUI_DownloadList * list);
+
+/**
+ * Free the subtree (assumes all threads have already been stopped and
+ * that the FSUI lock is either held or that we are in FSUI stop!).
+ */
+void freeDownloadList(FSUI_DownloadList * list);
+
+/**
  * Cleanup the FSUI context (removes dead entries from
- * activeThreads / activeSearches).
+ * activeThreads / activeSearches / activeDownloads).
  */
 void cleanupFSUIThreadList(FSUI_Context * ctx);
 
 
-/* from download.c */
+/* FOR RESUME: from download.c */
 /**
  * Thread that downloads a file.
  */
@@ -283,7 +353,7 @@
 
 /* from search.c */
 /**
- * Thread that searches for data.
+ * FOR RESUME: Thread that searches for data.
  */
 void * searchThread(FSUI_SearchList * pos);
 

Modified: GNUnet/src/applications/fs/fsui/search.c
===================================================================
--- GNUnet/src/applications/fs/fsui/search.c    2005-06-13 20:56:27 UTC (rev 
924)
+++ GNUnet/src/applications/fs/fsui/search.c    2005-06-14 16:58:05 UTC (rev 
925)
@@ -46,7 +46,7 @@
   pos->resultsReceived[pos->sizeResultsReceived-1].meta
     = ECRS_dupMetaData(fi->meta);
 
-  event.type = search_result;
+  event.type = FSUI_search_result;
   event.data.SearchResult.fi = *fi;
   event.data.SearchResult.searchURI = pos->uri;
   pos->ctx->ecb(pos->ctx->ecbClosure,

Modified: GNUnet/src/applications/fs/fsui/unindex.c
===================================================================
--- GNUnet/src/applications/fs/fsui/unindex.c   2005-06-13 20:56:27 UTC (rev 
924)
+++ GNUnet/src/applications/fs/fsui/unindex.c   2005-06-14 16:58:05 UTC (rev 
925)
@@ -49,7 +49,7 @@
                             UnindexThreadClosure * utc) {
   FSUI_Event event;
 
-  event.type = unindex_progress;
+  event.type = FSUI_unindex_progress;
   event.data.UnindexProgress.completed = completedBytes;
   event.data.UnindexProgress.total = totalBytes;
   event.data.UnindexProgress.filename = utc->filename;
@@ -74,12 +74,12 @@
                         NULL,
                         NULL);
   if (ret == OK) {
-    event.type = unindex_complete;
+    event.type = FSUI_unindex_complete;
     event.data.UnindexComplete.total = getFileSize(utc->filename);
     event.data.UnindexComplete.filename = utc->filename;
     event.data.UnindexComplete.start_time = utc->start_time;
   } else {
-    event.type = unindex_error;
+    event.type = FSUI_unindex_error;
     event.data.message = _("Unindex failed.\n");
   }
   FREE(utc->filename);

Modified: GNUnet/src/applications/fs/fsui/upload.c
===================================================================
--- GNUnet/src/applications/fs/fsui/upload.c    2005-06-13 20:56:27 UTC (rev 
924)
+++ GNUnet/src/applications/fs/fsui/upload.c    2005-06-14 16:58:05 UTC (rev 
925)
@@ -73,7 +73,7 @@
   cron_t now;
 
   cronTime(&now);
-  event.type = upload_progress;
+  event.type = FSUI_upload_progress;
   event.data.UploadProgress.completed = completedBytes;
   event.data.UploadProgress.total = totalBytes;
   event.data.UploadProgress.filename = utc->filename;
@@ -160,7 +160,7 @@
                            NULL,
                            uri);
       if (ret == OK) {
-       event.type = upload_complete;
+       event.type = FSUI_upload_complete;
        event.data.UploadComplete.total = utc->main_total;
        event.data.UploadComplete.filename = STRDUP(dirName);
        event.data.UploadComplete.uri = *uri;
@@ -219,7 +219,7 @@
                    NULL,
                    NULL,
                    &uri);
-    event.type = upload_complete;
+    event.type = FSUI_upload_complete;
     event.data.UploadComplete.total = utc->main_total;
     event.data.UploadComplete.filename = utc->filename;
     event.data.UploadComplete.uri = uri;
@@ -336,7 +336,7 @@
                          NULL,
                          &uri);
     if (ret == OK) {
-      event.type = upload_complete;
+      event.type = FSUI_upload_complete;
       event.data.UploadComplete.total = utc->main_total;
       event.data.UploadComplete.filename = utc->filename;
       event.data.UploadComplete.uri = uri;
@@ -345,7 +345,7 @@
       event.data.UploadComplete.is_recursive = NO;
       event.data.UploadComplete.main_filename = utc->main_filename;
     } else {
-      event.type = upload_error;
+      event.type = FSUI_upload_error;
       event.data.message = _("Upload failed.\n");
     }
     utc->ctx->ecb(utc->ctx->ecbClosure,
@@ -384,14 +384,14 @@
         0);
     
     if (ret != OK) {
-      event.type = upload_error;
+      event.type = FSUI_upload_error;
       event.data.message = _("Upload failed.\n");
       utc->ctx->ecb(utc->ctx->ecbClosure,
                    &event);
     } /* for success, uploadDirectory sends event already! */
     utc->filename = NULL;
   } else {
-    event.type = upload_error;
+    event.type = FSUI_upload_error;
     event.data.message = _("Cannot upload directory without using 
recursion.\n");
     utc->ctx->ecb(utc->ctx->ecbClosure,
                  &event);

Modified: GNUnet/src/applications/fs/tools/gnunet-download.c
===================================================================
--- GNUnet/src/applications/fs/tools/gnunet-download.c  2005-06-13 20:56:27 UTC 
(rev 924)
+++ GNUnet/src/applications/fs/tools/gnunet-download.c  2005-06-14 16:58:05 UTC 
(rev 925)
@@ -149,7 +149,7 @@
   int * ok = okVal;
 
   switch (event->type) {
-  case download_progress:
+  case FSUI_download_progress:
     if (YES == testConfigurationString("GNUNET-DOWNLOAD",
                                       "VERBOSE",
                                       "YES")) {
@@ -162,22 +162,38 @@
       printf("\r");
     }
     break;
-  case download_error:
+  case FSUI_download_aborted:
+    if (FSUI_getDownloadParent(event->data.DownloadError.pos) == NULL) {
+      /* top-download aborted */
+      printf(_("Error downloading: %s\n"),
+            event->data.DownloadError.message);
+      *ok = SYSERR;
+      SEMAPHORE_UP(signalFinished);
+    } else {
+      /* child aborted, maybe FSUI thread
+        policy, ignore?  How can this
+        happen anyway with gnunet-download? */
+    }
+    break;
+  case FSUI_download_error:
     printf(_("Error downloading: %s\n"),
-          event->data.message);
+          event->data.DownloadError.message);
     *ok = SYSERR;
     SEMAPHORE_UP(signalFinished);
     break;
-  case download_complete:
-    printf(_("\nDownload of file '%s' complete.  Speed was %8.3f kilobyte per 
second.\n"),
-          event->data.DownloadProgress.filename,
-          (event->data.DownloadProgress.completed/1024.0) /
-          (((double)(cronTime(NULL)-(event->data.DownloadProgress.start_time - 
1)))
-           / (double)cronSECONDS) );
-    if (ECRS_equalsUri(event->data.DownloadProgress.main_uri,
-                      event->data.DownloadProgress.uri) ) {
-      *ok = OK;
-      SEMAPHORE_UP(signalFinished);
+  case FSUI_download_complete:
+    if ( (event->data.DownloadProgress.completed ==
+         event->data.DownloadProgress.total) ) {
+      printf(_("\nDownload of file '%s' complete.  Speed was %8.3f kilobyte 
per second.\n"),
+            event->data.DownloadProgress.filename,
+            (event->data.DownloadProgress.completed/1024.0) /
+            (((double)(cronTime(NULL)-(event->data.DownloadProgress.start_time 
- 1)))
+             / (double)cronSECONDS) );
+      if (ECRS_equalsUri(event->data.DownloadProgress.main_uri,
+                        event->data.DownloadProgress.uri)) {
+       *ok = OK;
+       SEMAPHORE_UP(signalFinished);
+      }
     }
     break;
   default:

Modified: GNUnet/src/applications/fs/tools/gnunet-insert.c
===================================================================
--- GNUnet/src/applications/fs/tools/gnunet-insert.c    2005-06-13 20:56:27 UTC 
(rev 924)
+++ GNUnet/src/applications/fs/tools/gnunet-insert.c    2005-06-14 16:58:05 UTC 
(rev 925)
@@ -121,7 +121,7 @@
   char * fstring;
 
   switch(event->type) {
-  case upload_progress:
+  case FSUI_upload_progress:
     if (*verboselevel == YES) {
       delta = event->data.UploadProgress.eta - cronTime(NULL);
       PRINTF(
@@ -132,7 +132,7 @@
       printf("\r");
     }
     break;
-  case upload_complete:
+  case FSUI_upload_complete:
     if (*verboselevel == YES) {
       delta = event->data.UploadComplete.eta - 
event->data.UploadComplete.start_time;
       PRINTF(
@@ -157,7 +157,7 @@
     }
 
     break;
-  case upload_error:
+  case FSUI_upload_error:
     printf(_("\nError uploading file: %s\n"),
           event->data.message);
     errorCode = 1;

Modified: GNUnet/src/applications/fs/tools/gnunet-search.c
===================================================================
--- GNUnet/src/applications/fs/tools/gnunet-search.c    2005-06-13 20:56:27 UTC 
(rev 924)
+++ GNUnet/src/applications/fs/tools/gnunet-search.c    2005-06-14 16:58:05 UTC 
(rev 925)
@@ -58,7 +58,7 @@
   char * uri;
   char * filename;
 
-  if (event->type != search_result)
+  if (event->type != FSUI_search_result)
     return;
 
   /* retain URIs for possible directory dump later */

Modified: GNUnet/src/applications/fs/tools/gnunet-unindex.c
===================================================================
--- GNUnet/src/applications/fs/tools/gnunet-unindex.c   2005-06-13 20:56:27 UTC 
(rev 924)
+++ GNUnet/src/applications/fs/tools/gnunet-unindex.c   2005-06-14 16:58:05 UTC 
(rev 925)
@@ -44,7 +44,7 @@
   unsigned long long delta;
 
   switch(event->type) {
-  case unindex_progress:
+  case FSUI_unindex_progress:
     if (*verboselevel == YES) {
       delta = event->data.UploadProgress.eta - cronTime(NULL);
       PRINTF(_("%16llu of %16llu bytes unindexed (estimating %llu seconds to 
completion)                "),
@@ -54,7 +54,7 @@
       printf("\r");
     }
     break;
-  case unindex_complete:
+  case FSUI_unindex_complete:
     if (*verboselevel == YES) {
       delta = event->data.UploadComplete.eta - 
event->data.UploadComplete.start_time;
       PRINTF(
@@ -67,7 +67,7 @@
       : (double) (event->data.UploadComplete.total / 1024.0 * cronSECONDS / 
delta));
     }
     break;
-  case unindex_error:
+  case FSUI_unindex_error:
     printf(_("\nError unindexing file: %s\n"),
           event->data.message);
     errorCode = 1;

Modified: GNUnet/src/include/gnunet_fsui_lib.h
===================================================================
--- GNUnet/src/include/gnunet_fsui_lib.h        2005-06-13 20:56:27 UTC (rev 
924)
+++ GNUnet/src/include/gnunet_fsui_lib.h        2005-06-14 16:58:05 UTC (rev 
925)
@@ -65,31 +65,46 @@
 #include "gnunet_ecrs_lib.h"
 
 /**
+ * Entry representing an FSUI download.  FSUI downloads form a tree
+ * (for properly representing recursive downloads) with an invisible
+ * root (for multiple parallel downloads).
+ *
+ * FSUI hands out references of this type to allow clients to access
+ * information about active downloads.
+ *
+ * Structs of this type MUST NOT be stored in anything but local
+ * variables (!) by FSUI clients.  This will ensure that the
+ * references are always valid.
+ */
+struct FSUI_DownloadList;
+
+/**
  * @brief types of FSUI events.
  */
 enum FSUI_EventType {
   /**
    * We found a new search result.
    */
-  search_result,
-  search_error,
-  download_progress,
-  download_complete,
-  download_error,
-  upload_progress,
-  upload_complete,
-  upload_error,
-  unindex_progress,
-  unindex_complete,
-  unindex_error,
+  FSUI_search_result,
+  FSUI_search_error,
+  FSUI_download_progress,
+  FSUI_download_complete,
+  FSUI_download_aborted,
+  FSUI_download_error,
+  FSUI_upload_progress,
+  FSUI_upload_complete,
+  FSUI_upload_error,
+  FSUI_unindex_progress,
+  FSUI_unindex_complete,
+  FSUI_unindex_error,
   /**
    * Connection status with gnunetd changed.
    */
-  gnunetd_connected,
+  FSUI_gnunetd_connected,
   /**
    * Connection status with gnunetd changed.
    */
-  gnunetd_disconnected,
+  FSUI_gnunetd_disconnected,
 };
 
 /**
@@ -165,9 +180,30 @@
        * main URI? (otherwise equal to uri);
        */
       struct ECRS_URI * main_uri;
+      /**
+       * What file in the download tree are we
+       * refering to?
+       */
+      struct FSUI_DownloadList * pos;
     } DownloadProgress;
+    /**
+     * DownloadError is used for both
+     * download_aborted and download_error
+     * message types.
+     */
     struct {
       /**
+       * Error message.
+       */
+      const char * message;
+      /**
+       * What file in the download tree are we
+       * refering to?
+       */
+      struct FSUI_DownloadList * pos;
+    } DownloadError;
+    struct {
+      /**
        * How far are we? (for the current file)
        */
       unsigned long long completed;
@@ -266,15 +302,13 @@
 struct FSUI_Context;
 
 /**
- * Generic callback for all kinds of FSUI progress
- * and error messages.  This function will be called
- * for download progress, download completion, upload
- * progress and completion, search results, etc.
+ * Generic callback for all kinds of FSUI progress and error messages.
+ * This function will be called for download progress, download
+ * completion, upload progress and completion, search results, etc.
  *
- * The details of the argument format are yet to be
- * defined.  What FSUI guarantees is that only one
- * thread at a time will call the callback (so it
- * need not be re-entrant).
+ * The details of the argument format are yet to be defined.  What
+ * FSUI guarantees is that only one thread at a time will call the
+ * callback (so it need not be re-entrant).
  */
 typedef void (*FSUI_EventCallback)(void * cls,
                                   const FSUI_Event * event);
@@ -323,9 +357,12 @@
 /**
  * Iterator over active downloads.
  *
+ * @param pos What file in the download tree are we
+ * refering to?
  * @return OK to continue iteration, SYSERR to abort
  */
 typedef int (*FSUI_DownloadIterator)(void * cls,
+                                    const struct FSUI_DownloadList * pos,
                                     const char * filename,
                                     const struct ECRS_URI * uri,
                                     unsigned long long filesize,
@@ -388,6 +425,7 @@
  *  if keywords is not legal (i.e. empty).
  */
 struct ECRS_URI * FSUI_parseCharKeywordURI(const char * keywords); /* helper.c 
*/
+
 /**
  * Create an ECRS URI from a user-supplied command line of keywords.
  * The command line may contain the reserved word 'AND' to create a
@@ -447,7 +485,10 @@
                       const char * filename); /* download.c */
 
 /**
- * Abort a download.
+ * Abort a download.  If the URI was for a recursive
+ * download, all sub-downloads will also be aborted.
+ * Cannot be used to terminate a single file download
+ * that is part of a recursive download.
  *
  * @return SYSERR if no such download is pending
  */
@@ -460,12 +501,23 @@
  * downloads, FSUI clients should listen closely
  * to the FSUI_EventCallback to not miss completion
  * events.
+ *
+ * @param root subtree to iterate over, use
+ *        NULL for all top-level downloads
  */
 int FSUI_listDownloads(struct FSUI_Context * ctx,
+                      const struct FSUI_DownloadList * root,
                       FSUI_DownloadIterator iter,
                       void * closure); /* download.c */
 
 /**
+ * Get parent of active download. 
+ * @return NULL if there is no parent
+ */
+const struct FSUI_DownloadList * 
+FSUI_getDownloadParent(const struct FSUI_DownloadList * child); /* download.c 
*/
+
+/**
  * Start uploading a file.  Note that an upload cannot be stopped once
  * started (not necessary anyway), but it can fail.  The function also
  * automatically the uploaded file in the global keyword space under
@@ -526,16 +578,6 @@
                          const struct ECRS_URI * uri,
                          const char * dirname); /* download.c */
 
-/**
- * Abort a download.
- *
- * @return OK on success, SYSERR if no such download is
- *  pending
- */
-int FSUI_stopDownloadAll(struct FSUI_Context * ctx,
-                        const struct ECRS_URI * uri,
-                        const char * dirname); /* download.c */
-               
 /* ******************** collections API **************** */
 
 /**
@@ -567,31 +609,27 @@
  * changed since the last publication.  If we are currently not
  * collecting, this function does nothing.
  *
- * Note that clients typically don't have to call this
- * function explicitly.  FSUI will call the function on
- * exit (for sporadically updated collections), on any
- * change to the collection (for immediately updated
- * content) or when the publication time has arrived
- * (for periodically updated collections).
+ * Note that clients typically don't have to call this function
+ * explicitly.  FSUI will call the function on exit (for sporadically
+ * updated collections), on any change to the collection (for
+ * immediately updated content) or when the publication time has
+ * arrived (for periodically updated collections).
  *
- * However, clients may want to call this function if
- * explicit publication of an update at another
- * time is desired.
+ * However, clients may want to call this function if explicit
+ * publication of an update at another time is desired.
  */
 void FSUI_publishCollectionNow(struct FSUI_Context * ctx);
 
 /**
- * If we are currently building a collection, publish
- * the given file information in that collection.
- * If we are currently not collecting, this function
- * does nothing.
+ * If we are currently building a collection, publish the given file
+ * information in that collection.  If we are currently not
+ * collecting, this function does nothing.
  *
- * Note that clients typically don't have to call this
- * function explicitly -- by using the FSUI library it
- * should be called automatically by FSUI code whenever
- * needed.  However, the function maybe useful if you're
- * inserting files using libECRS directly or need other
- * ways to explicitly extend a collection.
+ * Note that clients typically don't have to call this function
+ * explicitly -- by using the FSUI library it should be called
+ * automatically by FSUI code whenever needed.  However, the function
+ * maybe useful if you're inserting files using libECRS directly or
+ * need other ways to explicitly extend a collection.
  */
 void FSUI_publishToCollection(struct FSUI_Context * ctx,
                              const ECRS_FileInfo * fi);
@@ -619,9 +657,8 @@
                         struct ECRS_URI ** root); /* namespace_info.c */
 
 /**
- * Delete a local namespace.  Only prevents future insertions
- * into the namespace, does not delete any content from
- * the network!
+ * Delete a local namespace.  Only prevents future insertions into the
+ * namespace, does not delete any content from the network!
  *
  * @return OK on success, SYSERR on error
  */
@@ -635,9 +672,9 @@
                       int delta); /* namespace_info.c */
 
 /**
- * Add a namespace to the set of known namespaces.
- * For all namespace advertisements that we discover
- * FSUI should automatically call this function.
+ * Add a namespace to the set of known namespaces.  For all namespace
+ * advertisements that we discover FSUI should automatically call this
+ * function.
  *
  * @param ns the namespace identifier
  */
@@ -724,7 +761,6 @@
  */
 void FSUI_trackURIS(int onOff); /* file_info.c */
 
-
 /**
  * Get the FSUI URI tracking status.
  *
@@ -733,10 +769,9 @@
 int FSUI_trackStatus(void); /* file_info.c */
 
 /**
- * Makes a URI available for directory building.
- * This function is automatically called by all FSUI
- * functions and only in the interface for clients that
- * call ECRS directly.
+ * Makes a URI available for directory building.  This function is
+ * automatically called by all FSUI functions and only in the
+ * interface for clients that call ECRS directly.
  */
 void FSUI_trackURI(const ECRS_FileInfo * fi); /* file_info.c */
 

Modified: GNUnet/todo
===================================================================
--- GNUnet/todo 2005-06-13 20:56:27 UTC (rev 924)
+++ GNUnet/todo 2005-06-14 16:58:05 UTC (rev 925)
@@ -1,12 +1,16 @@
 0.7.0pre3:
-- gnunet-gtk (debug)
+- gnunet-gtk:
+  * make directories work [ CG ]
+- FSUI:
+  * make (recursive) downloads work (test/debug) [ CG ]
+- GAP:
+  * fix Nils' assertion failure/bug [ CG ]
 - gnunet-setup: [Nils]
   * gconfig: fix focus changes
   * wizards: restrict user & service creation to platforms
     known to be working.  
 
 0.7.0 [6'05?] (aka "compatibility? what's that?"):
-- FSUI: recursive directory download crashes (i.e. on exit)
 - Missing Features:
   * resolve "FIXME 0.7": only sqlite magic factor missing! [Nils]
   * #593 (gnunet-setup): php-ification for i18n [ Nils ]
@@ -33,8 +37,6 @@
 0.7.1 (aka "stabilization"):
 - Optimizations:
   * spread out scanning done in topology_*.c?
-  * fsui download: limit parallelism (currently unlimited, old gnunet-download 
allowed
-    user to specify maximum amount of parallelism) [ tricky ]
 - gnunet-chat
 - DHT:
   * make dht tests work





reply via email to

[Prev in Thread] Current Thread [Next in Thread]