⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 download.c

📁 GNUnet是一个安全的点对点网络框架
💻 C
📖 第 1 页 / 共 2 页
字号:
/*     This file is part of GNUnet.     (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008 Christian Grothoff (and other contributing authors)     GNUnet is free software; you can redistribute it and/or modify     it under the terms of the GNU General Public License as published     by the Free Software Foundation; either version 2, or (at your     option) any later version.     GNUnet is distributed in the hope that it will be useful, but     WITHOUT ANY WARRANTY; without even the implied warranty of     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     General Public License for more details.     You should have received a copy of the GNU General Public License     along with GNUnet; see the file COPYING.  If not, write to the     Free Software Foundation, Inc., 59 Temple Place - Suite 330,     Boston, MA 02111-1307, USA.*//** * @file applications/fs/ecrs/download.c * @brief DOWNLOAD helper methods (which do the real work). * @author Christian Grothoff */#include "platform.h"#include "gnunet_protocols.h"#include "gnunet_ecrs_lib.h"#include "gnunet_fs_lib.h"#include "gnunet_identity_lib.h"#include "ecrs_core.h"#include "ecrs.h"#include "fs.h"#include "tree.h"#define DEBUG_DOWNLOAD GNUNET_NO/** * Node-specific data (not shared, keep small!). 152 bytes. * Nodes are kept in a doubly-linked list. */struct Node{  /**   * Pointer to shared data between all nodes (request manager,   * progress data, etc.).   */  struct GNUNET_ECRS_DownloadContext *ctx;  /**   * Previous entry in DLL.   */  struct Node *prev;  /**   * Next entry in DLL.   */  struct Node *next;  /**   * What is the GNUNET_EC_ContentHashKey for this block?   */  GNUNET_EC_ContentHashKey chk;  /**   * At what offset (on the respective level!) is this   * block?   */  unsigned long long offset;  /**   * 0 for dblocks, >0 for iblocks.   */  unsigned int level;};/** * @brief structure that keeps track of currently pending requests for *        a download * * Handle to the state of a request manager.  Here we keep track of * which queries went out with which priorities and which nodes in * the merkle-tree are waiting for the replies. */struct GNUNET_ECRS_DownloadContext{  /**   * Total number of bytes in the file.   */  unsigned long long total;  /**   * Number of bytes already obtained   */  unsigned long long completed;  /**   * Starting-offset in file (for partial download)   */  unsigned long long offset;  /**   * Length of the download (starting at offset).   */  unsigned long long length;  /**   * Time download was started.   */  GNUNET_CronTime startTime;  /**   * Doubly linked list of all pending requests (head)   */  struct Node *head;  /**   * Doubly linked list of all pending requests (tail)   */  struct Node *tail;  /**   * FSLIB context for issuing requests.   */  struct GNUNET_FS_SearchContext *sctx;  /**   * Context for error reporting.   */  struct GNUNET_GE_Context *ectx;  /**   * Configuration information.   */  struct GNUNET_GC_Configuration *cfg;  /**   * The file handle.   */  int handle;  /**   * Do we exclusively own this sctx?   */  int my_sctx;  /**   * The base-filename   */  char *filename;  /**   * Main thread running the operation.   */  struct GNUNET_ThreadHandle *main;  /**   * Function to call when we make progress.   */  GNUNET_ECRS_DownloadProgressCallback dpcb;  /**   * Extra argument to dpcb.   */  void *dpcbClosure;  /**   * Identity of the peer having the content, or all-zeros   * if we don't know of such a peer.   */  GNUNET_PeerIdentity target;  /**   * Abort?  Flag that can be set at any time   * to abort the RM as soon as possible.  Set   * to GNUNET_YES during orderly shutdown,   * set to GNUNET_SYSERR on error.   */  int abortFlag;  /**   * Do we have a specific peer from which we download   * from?   */  int have_target;  /**   * Desired anonymity level for the download.   */  unsigned int anonymityLevel;  /**   * The depth of the file-tree.   */  unsigned int treedepth;};static intcontent_receive_callback (const GNUNET_HashCode * query,                          const GNUNET_DatastoreValue * reply, void *cls,                          unsigned long long uid);/** * Close the files and free the associated resources. * * @param self reference to the download context */static voidfree_request_manager (struct GNUNET_ECRS_DownloadContext *rm){  struct Node *pos;  if (rm->abortFlag == GNUNET_NO)    rm->abortFlag = GNUNET_YES;  if (rm->my_sctx == GNUNET_YES)    GNUNET_FS_destroy_search_context (rm->sctx);  else    GNUNET_FS_suspend_search_context (rm->sctx);  while (rm->head != NULL)    {      pos = rm->head;      if (rm->my_sctx != GNUNET_YES)        GNUNET_FS_stop_search (rm->sctx, &content_receive_callback, pos);      rm->head = pos->next;      GNUNET_free (pos);    }  if (rm->my_sctx != GNUNET_YES)    GNUNET_FS_resume_search_context (rm->sctx);  rm->tail = NULL;  if (rm->handle >= 0)    CLOSE (rm->handle);  if (rm->main != NULL)    GNUNET_thread_release_self (rm->main);  GNUNET_free_non_null (rm->filename);  rm->sctx = NULL;  GNUNET_free (rm);}/** * Read method. * * @param self reference to the download context * @param level level in the tree to read/write at * @param pos position where to read or write * @param buf where to read from or write to * @param len how many bytes to read or write * @return number of bytes read, GNUNET_SYSERR on error */static intread_from_files (struct GNUNET_ECRS_DownloadContext *self,                 unsigned int level,                 unsigned long long pos, void *buf, unsigned int len){  if ((level > 0) || (self->handle == -1))    return GNUNET_SYSERR;  LSEEK (self->handle, pos, SEEK_SET);  return READ (self->handle, buf, len);}/** * Write method. * * @param self reference to the download context * @param level level in the tree to write to * @param pos position where to  write * @param buf where to write to * @param len how many bytes to write * @return number of bytes written, GNUNET_SYSERR on error */static intwrite_to_files (struct GNUNET_ECRS_DownloadContext *self,                unsigned int level,                unsigned long long pos, void *buf, unsigned int len){  int ret;  if (level > 0)    return len;                 /* lie -- no more temps */  if (self->handle == -1)    return len;  LSEEK (self->handle, pos, SEEK_SET);  ret = WRITE (self->handle, buf, len);  if (ret != len)    GNUNET_GE_LOG_STRERROR_FILE (self->ectx,                                 GNUNET_GE_ERROR | GNUNET_GE_BULK |                                 GNUNET_GE_USER, "write", self->filename);  return ret;}/** * Queue a request for execution. * * @param rm the request manager struct from createRequestManager * @param node the node to call once a reply is received */static voidadd_request (struct Node *node){  struct GNUNET_ECRS_DownloadContext *rm = node->ctx;  node->next = rm->head;  if (node->next != NULL)    node->next->prev = node;  node->prev = NULL;  rm->head = node;  if (rm->tail == NULL)    rm->tail = node;  GNUNET_FS_start_search (rm->sctx,                          rm->have_target == GNUNET_NO ? NULL : &rm->target,                          GNUNET_ECRS_BLOCKTYPE_DATA, 1,                          &node->chk.query,                          rm->anonymityLevel,                          &content_receive_callback, node);}static voidsignal_abort (struct GNUNET_ECRS_DownloadContext *rm, const char *msg){  rm->abortFlag = GNUNET_SYSERR;  if ((rm->head != NULL) && (rm->dpcb != NULL))    rm->dpcb (rm->length + 1, 0, 0, 0, msg, 0, rm->dpcbClosure);  GNUNET_thread_stop_sleep (rm->main);}/** * Dequeue a request. * * @param self the request manager struct from createRequestManager * @param node the block for which the request is canceled */static voiddelete_node (struct Node *node){  struct GNUNET_ECRS_DownloadContext *rm = node->ctx;  if (node->prev == NULL)    rm->head = node->next;  else    node->prev->next = node->next;  if (node->next == NULL)    rm->tail = node->prev;  else    node->next->prev = node->prev;  GNUNET_free (node);  if (rm->head == NULL)    GNUNET_thread_stop_sleep (rm->main);}/** * Compute how many bytes of data are stored in * this node. */static unsigned intget_node_size (const struct Node *node){  unsigned int i;  unsigned int ret;  unsigned long long rsize;  unsigned long long spos;  unsigned long long epos;  GNUNET_GE_ASSERT (node->ctx->ectx, node->offset < node->ctx->total);  if (node->level == 0)    {      ret = GNUNET_ECRS_DBLOCK_SIZE;      if (node->offset + (unsigned long long) ret > node->ctx->total)        ret = (unsigned int) (node->ctx->total - node->offset);#if DEBUG_DOWNLOAD      GNUNET_GE_LOG (node->ctx->rm->ectx,                     GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,                     "Node at offset %llu and level %d has size %u\n",                     node->offset, node->level, ret);#endif      return ret;    }  rsize = GNUNET_ECRS_DBLOCK_SIZE;  for (i = 0; i < node->level - 1; i++)    rsize *= GNUNET_ECRS_CHK_PER_INODE;  spos = rsize * (node->offset / sizeof (GNUNET_EC_ContentHashKey));  epos = spos + rsize * GNUNET_ECRS_CHK_PER_INODE;  if (epos > node->ctx->total)    epos = node->ctx->total;  ret = (epos - spos) / rsize;  if (ret * rsize < epos - spos)    ret++;                      /* need to round up! */#if DEBUG_DOWNLOAD  GNUNET_GE_LOG (node->ctx->rm->ectx,                 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,                 "Node at offset %llu and level %d has size %u\n",                 node->offset, node->level,                 ret * sizeof (GNUNET_EC_ContentHashKey));#endif  return ret * sizeof (GNUNET_EC_ContentHashKey);}/** * Notify client about progress. */static voidnotify_client_about_progress (const struct Node *node,                              const char *data, unsigned int size){  struct GNUNET_ECRS_DownloadContext *rm = node->ctx;  GNUNET_CronTime eta;  if ((rm->abortFlag != GNUNET_NO) || (node->level != 0))    return;  rm->completed += size;  eta = GNUNET_get_time ();  if (rm->completed > 0)    eta = (GNUNET_CronTime) (rm->startTime +                             (((double) (eta - rm->startTime) /                               (double) rm->completed)) *                             (double) rm->length);  if (rm->dpcb != NULL)    rm->dpcb (rm->length,              rm->completed, eta, node->offset, data, size, rm->dpcbClosure);}/** * DOWNLOAD children of this GNUNET_EC_IBlock. * * @param node the node for which the children should be downloaded * @param data data for the node * @param size size of data */static void iblock_download_children (const struct Node *node,                                      const char *data, unsigned int size);/** * Check if self block is already present on the drive.  If the block * is a dblock and present, the ProgressModel is notified. If the * block is present and it is an iblock, downloading the children is * triggered. * * Also checks if the block is within the range of blocks * that we are supposed to download.  If not, the method * returns as if the block is present but does NOT signal * progress. * * @param node that is checked for presence * @return GNUNET_YES if present, GNUNET_NO if not. */static intcheck_node_present (const struct Node *node){  int res;  int ret;  char *data;  unsigned int size;  GNUNET_HashCode hc;  size = get_node_size (node);  /* first check if node is within range.     For now, keeping it simple, we only do     this for level-0 nodes */  if ((node->level == 0) &&      ((node->offset + size < node->ctx->offset) ||       (node->offset >= node->ctx->offset + node->ctx->length)))    return GNUNET_YES;  data = GNUNET_malloc (size);  ret = GNUNET_NO;  res = read_from_files (node->ctx, node->level, node->offset, data, size);  if (res == size)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -