/**
 * Convert a string to an IP address.
 *
 * @param client where to send the IP address
 * @param hostname the hostname to resolve
 * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any"
 */
static void
get_ip_from_hostname (struct GNUNET_SERVER_Client *client, const char *hostname,
                      int af)
{
  int ret;
  struct GNUNET_SERVER_TransmitContext *tc;

  tc = GNUNET_SERVER_transmit_context_create (client);
  ret = GNUNET_NO;
#if HAVE_GETADDRINFO
  if (ret == GNUNET_NO)
    ret = getaddrinfo_resolve (tc, hostname, af);
#endif
#if HAVE_GETHOSTBYNAME2
  if (ret == GNUNET_NO)
    ret = gethostbyname2_resolve (tc, hostname, af);
#endif
#if HAVE_GETHOSTBYNAME
  if ((ret == GNUNET_NO) && ((af == AF_UNSPEC) || (af == PF_INET)))
    gethostbyname_resolve (tc, hostname);
#endif
  GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
                                              GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
  GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
}
/**
 * Handle INDEX_LIST_GET-message.
 *
 * @param cls closure
 * @param client identification of the client
 * @param message the actual message
 */
void
GNUNET_FS_handle_index_list_get (void *cls, struct GNUNET_SERVER_Client *client,
                                 const struct GNUNET_MessageHeader *message)
{
  struct GNUNET_SERVER_TransmitContext *tc;
  struct IndexInfoMessage *iim;
  char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;
  size_t slen;
  const char *fn;
  struct IndexInfo *pos;

  tc = GNUNET_SERVER_transmit_context_create (client);
  iim = (struct IndexInfoMessage *) buf;
  for (pos = indexed_files_head; NULL != pos; pos = pos->next)
  {
    fn = pos->filename;
    slen = strlen (fn) + 1;
    if (slen + sizeof (struct IndexInfoMessage) >=
        GNUNET_SERVER_MAX_MESSAGE_SIZE)
    {
      GNUNET_break (0);
      break;
    }
    iim->header.type = htons (GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_ENTRY);
    iim->header.size = htons (slen + sizeof (struct IndexInfoMessage));
    iim->reserved = 0;
    iim->file_id = pos->file_id;
    memcpy (&iim[1], fn, slen);
    GNUNET_SERVER_transmit_context_append_message (tc, &iim->header);
  }
  GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
                                              GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_END);
  GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_MINUTES);
}
/**
 * Client asked to resolve an address.  Process the request.
 *
 * @param cls unused
 * @param client the client
 * @param message the resolution request
 */
static void
clients_handle_address_to_string (void *cls,
                                  struct GNUNET_SERVER_Client *client,
                                  const struct GNUNET_MessageHeader *message)
{
  const struct AddressLookupMessage *alum;
  struct GNUNET_TRANSPORT_PluginFunctions *papi;
  const char *plugin_name;
  const char *address;
  uint32_t address_len;
  uint16_t size;
  struct GNUNET_SERVER_TransmitContext *tc;
  struct AddressToStringContext *actx;
  struct GNUNET_TIME_Relative rtimeout;
  int32_t numeric;

  size = ntohs (message->size);
  if (size < sizeof (struct AddressLookupMessage))
  {
    GNUNET_break (0);
    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
    return;
  }
  alum = (const struct AddressLookupMessage *) message;
  address_len = ntohs (alum->addrlen);
  if (size <= sizeof (struct AddressLookupMessage) + address_len)
  {
    GNUNET_break (0);
    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
    return;
  }
  address = (const char *) &alum[1];
  plugin_name = (const char *) &address[address_len];
  if ('\0' != plugin_name[size - sizeof (struct AddressLookupMessage) - address_len - 1])
  {
    GNUNET_break (0);
    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
    return;
  }
  rtimeout = GNUNET_TIME_relative_ntoh (alum->timeout);
  numeric = ntohs (alum->numeric_only);
  tc = GNUNET_SERVER_transmit_context_create (client);
  papi = GST_plugins_printer_find (plugin_name);
  if (NULL == papi)
  {
    GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
                                                GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
    GNUNET_SERVER_transmit_context_run (tc, rtimeout);
    return;
  }
  actx = GNUNET_new (struct AddressToStringContext);
  actx->tc = tc;
  GNUNET_CONTAINER_DLL_insert (a2s_head, a2s_tail, actx);
  GNUNET_SERVER_disable_receive_done_warning (client);
  papi->address_pretty_printer (papi->cls, plugin_name, address, address_len,
                                numeric, rtimeout, &transmit_address_to_client,
                                actx);
}
/**
 * Handle GET-ALL-message.
 *
 * @param cls closure
 * @param client identification of the client
 * @param message the actual message
 */
static void
handle_get_all (void *cls, struct GNUNET_SERVER_Client *client,
                const struct GNUNET_MessageHeader *message)
{
  struct GNUNET_SERVER_TransmitContext *tc;

  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s' message received\n", "GET_ALL");
  tc = GNUNET_SERVER_transmit_context_create (client);
  GNUNET_CONTAINER_multihashmap_iterate (hostmap, &add_to_tc, tc);
  GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
                                              GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END);
  GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
}
/**
 * Handle GET-message.
 *
 * @param cls closure
 * @param client identification of the client
 * @param message the actual message
 */
static void
handle_get (void *cls, struct GNUNET_SERVER_Client *client,
            const struct GNUNET_MessageHeader *message)
{
  const struct ListPeerMessage *lpm;
  struct GNUNET_SERVER_TransmitContext *tc;

  lpm = (const struct ListPeerMessage *) message;
  GNUNET_break (0 == ntohl (lpm->reserved));
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s' message received for peer `%4s'\n",
              "GET", GNUNET_i2s (&lpm->peer));
  tc = GNUNET_SERVER_transmit_context_create (client);
  GNUNET_CONTAINER_multihashmap_get_multiple (hostmap, &lpm->peer.hashPubKey,
                                              &add_to_tc, tc);
  GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
                                              GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END);
  GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
}
/**
 * Handle UNINDEX-message.
 *
 * @param cls closure
 * @param client identification of the client
 * @param message the actual message
 */
void
GNUNET_FS_handle_unindex (void *cls, struct GNUNET_SERVER_Client *client,
                          const struct GNUNET_MessageHeader *message)
{
  const struct UnindexMessage *um;
  struct IndexInfo *pos;
  struct GNUNET_SERVER_TransmitContext *tc;
  int found;

  um = (const struct UnindexMessage *) message;
  if (0 != um->reserved)
  {
    GNUNET_break (0);
    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
    return;
  }
  found = GNUNET_NO;
  for (pos = indexed_files_head; NULL != pos; pos = pos->next)
  {
    if (0 == memcmp (&pos->file_id, &um->file_id, sizeof (struct GNUNET_HashCode)))
    {
      GNUNET_CONTAINER_DLL_remove (indexed_files_head,
				   indexed_files_tail,
				   pos);
      GNUNET_break (GNUNET_OK ==
                    GNUNET_CONTAINER_multihashmap_remove (ifm, &pos->file_id,
							  pos));
      GNUNET_free (pos);
      found = GNUNET_YES;
      break;
    }
  }
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Client requested unindexing of file `%s': %s\n",
              GNUNET_h2s (&um->file_id), found ? "found" : "not found");
  if (GNUNET_YES == found)
    write_index_list ();
  tc = GNUNET_SERVER_transmit_context_create (client);
  GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
                                              GNUNET_MESSAGE_TYPE_FS_UNINDEX_OK);
  GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_MINUTES);
}
Exemplo n.º 7
0
/**
 * Get an IP address as a string (works for both IPv4 and IPv6).  Note
 * that the resolution happens asynchronously and that the first call
 * may not immediately result in the FQN (but instead in a
 * human-readable IP address).
 *
 * @param client handle to the client making the request (for sending the reply)
 * @param af AF_INET or AF_INET6
 * @param ip `struct in_addr` or `struct in6_addr`
 */
static void
get_ip_as_string (struct GNUNET_SERVER_Client *client,
                  int af,
		  const void *ip)
{
  struct IPCache *pos;
  struct IPCache *next;
  struct GNUNET_TIME_Absolute now;
  struct GNUNET_SERVER_TransmitContext *tc;
  size_t ip_len;
  struct in6_addr ix;

  switch (af)
  {
  case AF_INET:
    ip_len = sizeof (struct in_addr);
    break;
  case AF_INET6:
    ip_len = sizeof (struct in6_addr);
    break;
  default:
    GNUNET_assert (0);
  }
  now = GNUNET_TIME_absolute_get ();
  next = cache_head;
  while ( (NULL != (pos = next)) &&
	  ( (pos->af != af) ||
	    (pos->ip_len != ip_len) ||
	    (0 != memcmp (pos->ip, ip, ip_len))) )
  {
    next = pos->next;
    if (GNUNET_TIME_absolute_get_duration (pos->last_request).rel_value_us <
        60 * 60 * 1000 * 1000LL)
    {
      GNUNET_CONTAINER_DLL_remove (cache_head,
				   cache_tail,
				   pos);
      GNUNET_free_non_null (pos->addr);
      GNUNET_free (pos);
      continue;
    }
  }
  if (NULL != pos)
  {
    if ( (1 == inet_pton (af,
                          pos->ip,
                          &ix)) &&
         (GNUNET_TIME_absolute_get_duration (pos->last_request).rel_value_us >
          120 * 1000 * 1000LL) )
    {
      /* try again if still numeric AND 2 minutes have expired */
      GNUNET_free_non_null (pos->addr);
      pos->addr = NULL;
      cache_resolve (pos);
      pos->last_request = now;
    }
  }
  else
  {
    pos = GNUNET_malloc (sizeof (struct IPCache) + ip_len);
    pos->ip = &pos[1];
    memcpy (&pos[1], ip, ip_len);
    pos->last_request = now;
    pos->last_refresh = now;
    pos->ip_len = ip_len;
    pos->af = af;
    GNUNET_CONTAINER_DLL_insert (cache_head,
				 cache_tail,
				 pos);
    cache_resolve (pos);
  }
  tc = GNUNET_SERVER_transmit_context_create (client);
  if (NULL != pos->addr)
    GNUNET_SERVER_transmit_context_append_data (tc, pos->addr,
                                                strlen (pos->addr) + 1,
                                                GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
  else
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Reverse lookup failed\n");
  GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
                                              GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
  GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
}
/**
 * Handle INDEX_START-message.
 *
 * @param cls closure
 * @param client identification of the client
 * @param message the actual message
 */
void
GNUNET_FS_handle_index_start (void *cls, struct GNUNET_SERVER_Client *client,
                              const struct GNUNET_MessageHeader *message)
{
  const struct IndexStartMessage *ism;
  char *fn;
  uint16_t msize;
  struct IndexInfo *ii;
  size_t slen;
  uint64_t dev;
  uint64_t ino;
  uint64_t mydev;
  uint64_t myino;

  msize = ntohs (message->size);
  if ((msize <= sizeof (struct IndexStartMessage)) ||
      (((const char *) message)[msize - 1] != '\0'))
  {
    GNUNET_break (0);
    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
    return;
  }
  ism = (const struct IndexStartMessage *) message;
  if (0 != ism->reserved)
  {
    GNUNET_break (0);
    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
    return;
  }
  fn = GNUNET_STRINGS_filename_expand ((const char *) &ism[1]);
  if (fn == NULL)
  {
    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
    return;
  }
  dev = GNUNET_ntohll (ism->device);
  ino = GNUNET_ntohll (ism->inode);
  ism = (const struct IndexStartMessage *) message;
  slen = strlen (fn) + 1;
  ii = GNUNET_malloc (sizeof (struct IndexInfo) + slen);
  ii->filename = (const char *) &ii[1];
  memcpy (&ii[1], fn, slen);
  ii->file_id = ism->file_id;
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message for file `%s'\n",
              "START_INDEX", ii->filename);
  ii->tc = GNUNET_SERVER_transmit_context_create (client);
  mydev = 0;
  myino = 0;
  if (((dev != 0) || (ino != 0)) &&
      (GNUNET_OK == GNUNET_DISK_file_get_identifiers (fn, &mydev, &myino)) &&
      ((dev == mydev) && (ino == myino)))
  {
    /* fast validation OK! */
    signal_index_ok (ii);
    GNUNET_free (fn);
    return;
  }
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Mismatch in file identifiers (%llu != %llu or %u != %u), need to hash.\n",
              (unsigned long long) ino, (unsigned long long) myino,
              (unsigned int) dev, (unsigned int) mydev);
  /* slow validation, need to hash full file (again) */
  ii->fhc =
      GNUNET_CRYPTO_hash_file (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);
}
/**
 * Client asked to obtain information about a specific or all validation
 * processes
 *
 * @param cls unused
 * @param client the client
 * @param message the peer address information request
 */
static void
clients_handle_monitor_validation (void *cls, struct GNUNET_SERVER_Client *client,
                                const struct GNUNET_MessageHeader *message)
{
  static struct GNUNET_PeerIdentity all_zeros;
  struct GNUNET_SERVER_TransmitContext *tc;
  struct PeerMonitorMessage *msg;
  struct IterationContext pc;

  if (ntohs (message->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_REQUEST)
  {
    GNUNET_break (0);
    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
    return;
  }
  if (ntohs (message->size) != sizeof (struct ValidationMonitorMessage))
  {
    GNUNET_break (0);
    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
    return;
  }
  msg = (struct PeerMonitorMessage *) message;
  if ( (GNUNET_YES != ntohl (msg->one_shot)) &&
       (NULL != lookup_monitoring_client (val_monitoring_clients_head, client)) )
  {
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
                "ServerClient %p tried to start monitoring twice\n",
                client);
    GNUNET_break (0);
    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
    return;
  }
  GNUNET_SERVER_disable_receive_done_warning (client);
  pc.tc = tc = GNUNET_SERVER_transmit_context_create (client);

  /* Send initial list */
  if (0 == memcmp (&msg->peer, &all_zeros, sizeof (struct GNUNET_PeerIdentity)))
  {
    /* iterate over all neighbours */
    pc.all = GNUNET_YES;
    pc.id = msg->peer;
  }
  else
  {
    /* just return one neighbour */
    pc.all = GNUNET_NO;
    pc.id = msg->peer;
  }

  GST_validation_iterate (&send_validation_information, &pc);

  if (GNUNET_YES != ntohl (msg->one_shot))
  {
    setup_val_monitoring_client (client, &msg->peer);
  }
  else
  {
    GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
        GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_RESPONSE);
  }
  GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
}