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

📄 shared.c

📁 GNUnet是一个安全的点对点网络框架
💻 C
字号:
/*
      This file is part of GNUnet
      (C) 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., 51 Franklin Street, Fifth Floor,
      Boston, MA 02110-1301, USA.
 */

/**
 * @file fs/gap/shared.c
 * @brief shared helper functions and data structures
 * @author Christian Grothoff
 */

#include "platform.h"
#include "gnunet_protocols.h"
#include "shared.h"
#include "ondemand.h"
#include "fs.h"

/**
 * Free the request list, including the associated
 * list of pending requests, its entries in the
 * plans for various peers and known responses.
 */
void
GNUNET_FS_SHARED_free_request_list (struct RequestList *rl)
{
  struct ResponseList *repl;
  struct QueryPlanEntry *planl;

  while (rl->responses != NULL)
    {
      repl = rl->responses;
      rl->responses = repl->next;
      GNUNET_free (repl);
    }
  while (rl->plan_entries != NULL)
    {
      planl = rl->plan_entries;
      rl->plan_entries = planl->plan_entries_next;
      if (planl->next != NULL)
        planl->next->prev = planl->prev;
      else
        planl->list->tail = planl->prev;
      if (planl->prev != NULL)
        planl->prev->next = planl->next;
      else
        planl->list->head = planl->next;
      GNUNET_free (planl);
    }
  if (rl->bloomfilter != NULL)
    GNUNET_bloomfilter_free (rl->bloomfilter);
  GNUNET_FS_PT_change_rc (rl->primary_target, -1);
  GNUNET_FS_PT_change_rc (rl->response_target, -1);
  memset (rl, 0, sizeof (struct RequestList));  /* mark as freed */
  GNUNET_free (rl);
}



/**
 * Check if the given value is a valid
 * and new response for the given request list
 * entry.
 *
 * @param hc set to the hash of the data if successful
 * @return GNUNET_OK if so, GNUNET_NO if not new or not
 *         applicable, GNUNET_SYSERR on error
 */
int
GNUNET_FS_SHARED_test_valid_new_response (struct RequestList *rl,
                                          const GNUNET_HashCode * primary_key,
                                          unsigned int size,
                                          const GNUNET_EC_DBlock * data,
                                          GNUNET_HashCode * hc)
{
  struct ResponseList *seen;
  GNUNET_HashCode m;
  int ret;

  /* check that type and primary key match */
  if (((rl->type != GNUNET_ECRS_BLOCKTYPE_ANY) &&
       (rl->type != ntohl (data->type))) ||
      (0 != memcmp (primary_key, &rl->queries[0], sizeof (GNUNET_HashCode))))
    return GNUNET_NO;

  /* check that content matches query */
  ret = GNUNET_EC_is_block_applicable_for_query (ntohl (data->type),
                                                 size,
                                                 data,
                                                 &rl->queries[0],
                                                 rl->key_count,
                                                 &rl->queries[0]);
  if (ret != GNUNET_OK)
    return ret;

  /* check that this is a new response */
  GNUNET_hash (data, size, hc);
  GNUNET_FS_HELPER_mingle_hash (hc, rl->bloomfilter_mutator, &m);
  if ((rl->bloomfilter != NULL) &&
      (rl->response_client == NULL) &&
      (GNUNET_YES == GNUNET_bloomfilter_test (rl->bloomfilter, &m)))
    return GNUNET_NO;           /* not useful */
  /* bloomfilter should cover these already */
  seen = rl->responses;
  while (seen != NULL)
    {
      if (0 == memcmp (hc, &seen->hash, sizeof (GNUNET_HashCode)))
        return GNUNET_NO;
      seen = seen->next;
    }
  return GNUNET_OK;
}


/**
 * Mark the response corresponding to the given
 * hash code as seen (update linked list and bloom filter).
 */
void
GNUNET_FS_SHARED_mark_response_seen (struct RequestList *rl,
                                     const GNUNET_HashCode * hc)
{
  struct ResponseList *seen;
  GNUNET_HashCode m;

  if (rl->bloomfilter != NULL)
    {
      GNUNET_FS_HELPER_mingle_hash (hc, rl->bloomfilter_mutator, &m);
      GNUNET_bloomfilter_add (rl->bloomfilter, &m);
    }
  /* update seen list */
  seen = GNUNET_malloc (sizeof (struct ResponseList));
  seen->hash = *hc;
  seen->next = rl->responses;
  rl->responses = seen;
}


/**
 * If the data portion and type of the value match our value in the
 * closure, copy the header (priority, anonymity_level, expiration_time) and
 * abort the iteration: we found what we're looing for.  Otherwise
 * continue.
 */
int
GNUNET_FS_HELPER_complete_value_from_database_callback (const GNUNET_HashCode
                                                        * key,
                                                        const
                                                        GNUNET_DatastoreValue
                                                        * value,
                                                        void *closure,
                                                        unsigned long long
                                                        uid)
{
  GNUNET_DatastoreValue *comp = closure;

  if ((comp->size != value->size) ||
      (0 != memcmp (&value[1],
                    &comp[1],
                    ntohl (value->size) - sizeof (GNUNET_DatastoreValue))))
    return GNUNET_OK;
  *comp = *value;
  return GNUNET_SYSERR;
}


/**
 * Mingle hash with the mingle_number to
 * produce different bits.
 */
void
GNUNET_FS_HELPER_mingle_hash (const GNUNET_HashCode * in,
                              int mingle_number, GNUNET_HashCode * hc)
{
  GNUNET_HashCode m;

  GNUNET_hash (&mingle_number, sizeof (int), &m);
  GNUNET_hash_xor (&m, in, hc);
}


/**
 * The priority level imposes a bound on the maximum
 * value for the ttl that can be requested.
 *
 * @param ttl_in requested ttl
 * @param priority given priority
 * @return ttl_in if ttl_in is below the limit,
 *         otherwise the ttl-limit for the given priority
 */
int
GNUNET_FS_HELPER_bound_ttl (int ttl_in, unsigned int prio)
{
  if (ttl_in <= 0)
    return ttl_in;
  if (ttl_in >
      ((unsigned long long) prio) * GNUNET_GAP_TTL_DECREMENT /
      GNUNET_CRON_SECONDS)
    {
      if (((unsigned long long) prio) * GNUNET_GAP_TTL_DECREMENT /
          GNUNET_CRON_SECONDS >= (1 << 30))
        return 1 << 30;
      return (int) ((unsigned long long) prio) * GNUNET_GAP_TTL_DECREMENT /
        GNUNET_CRON_SECONDS;
    }
  return ttl_in;
}

/**
 * Send a response to a local client.
 *
 * @param request used to check if the response is new and
 *        unique, maybe NULL (skip test in that case)
 * @param hc set to hash of the message by this function
 *
 * @return GNUNET_OK on success,
 *         GNUNET_NO if the block should be deleted
 *         GNUNET_SYSERR to retry later
 */
int
GNUNET_FS_HELPER_send_to_client (GNUNET_CoreAPIForPlugins * coreAPI,
                                 const GNUNET_HashCode * key,
                                 const GNUNET_DatastoreValue * value,
                                 struct GNUNET_ClientHandle *client,
                                 struct RequestList *request,
                                 GNUNET_HashCode * hc)
{
  const GNUNET_EC_DBlock *dblock;
  CS_fs_reply_content_MESSAGE *msg;
  unsigned int size;
  GNUNET_DatastoreValue *enc;
  const GNUNET_DatastoreValue *use;
  int ret;

  size = ntohl (value->size) - sizeof (GNUNET_DatastoreValue);
  dblock = (const GNUNET_EC_DBlock *) &value[1];
  enc = NULL;
  if ((ntohl (dblock->type) == GNUNET_ECRS_BLOCKTYPE_ONDEMAND) &&
      (GNUNET_OK != GNUNET_FS_ONDEMAND_get_indexed_content (value,
                                                            key, &enc)))
    {
      return GNUNET_NO;         /* data corrupt: delete block! */
    }
  if (enc == NULL)
    use = value;
  else
    use = enc;
  size = ntohl (use->size) - sizeof (GNUNET_DatastoreValue);
  dblock = (const GNUNET_EC_DBlock *) &use[1];
  if (request != NULL)
    {
      if (GNUNET_OK != GNUNET_FS_SHARED_test_valid_new_response (request,
                                                                 key,
                                                                 size,
                                                                 dblock, hc))
        {
          GNUNET_free_non_null (enc);
          return GNUNET_SYSERR; /* duplicate or invalid */
        }
    }
  else
    {
      GNUNET_hash (dblock, size, hc);
    }
  msg = GNUNET_malloc (sizeof (CS_fs_reply_content_MESSAGE) + size);
  msg->header.type = htons (GNUNET_CS_PROTO_GAP_RESULT);
  msg->header.size = htons (sizeof (CS_fs_reply_content_MESSAGE) + size);
  msg->anonymity_level = use->anonymity_level;
  msg->expiration_time = use->expiration_time;
  memcpy (&msg[1], dblock, size);
  GNUNET_free_non_null (enc);
  ret = coreAPI->cs_send_message (client, &msg->header, GNUNET_NO);
  GNUNET_free (msg);
  if (ret == GNUNET_OK)
    return GNUNET_OK;
  return GNUNET_SYSERR;
}

/* end of shared.c */

⌨️ 快捷键说明

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