/**
 * We've validated the hash of the file we're about to index.  Signal
 * success to the client and update our internal data structures.
 *
 * @param ii the index info entry for the request
 */
static void
signal_index_ok (struct IndexInfo *ii)
{
  struct IndexInfo *ir;
  if (GNUNET_SYSERR ==
      GNUNET_CONTAINER_multihashmap_put (ifm, &ii->file_id,
                                         ii,
                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
  {
    ir = GNUNET_CONTAINER_multihashmap_get (ifm,
					    &ii->file_id);
    GNUNET_assert (NULL != ir);
    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                _
                ("Index request received for file `%s' is already indexed as `%s'.  Permitting anyway.\n"),
                ii->filename,
		ir->filename);           
    GNUNET_SERVER_transmit_context_append_data (ii->tc, NULL, 0,
                                                GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK);
    GNUNET_SERVER_transmit_context_run (ii->tc, GNUNET_TIME_UNIT_MINUTES);
    GNUNET_free (ii);
    return;
  }
  GNUNET_CONTAINER_DLL_insert (indexed_files_head,
			       indexed_files_tail,
			       ii);
  write_index_list ();
  GNUNET_SERVER_transmit_context_append_data (ii->tc, NULL, 0,
                                              GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK);
  GNUNET_SERVER_transmit_context_run (ii->tc, GNUNET_TIME_UNIT_MINUTES);
  ii->tc = NULL;
}
/**
 * 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);
}
/**
 * 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);
}
/**
 * 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);
}
/**
 * Take the given address and append it to the set of results sent back to
 * the client.
 *
 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
 * @param buf text to transmit
 */
static void
transmit_address_to_client (void *cls, const char *buf)
{
  struct AddressToStringContext *actx = cls;
  if (NULL == buf)
  {
    GNUNET_SERVER_transmit_context_append_data (actx->tc, NULL, 0,
                                                GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
    GNUNET_SERVER_transmit_context_run (actx->tc, GNUNET_TIME_UNIT_FOREVER_REL);
    GNUNET_CONTAINER_DLL_remove (a2s_head, a2s_tail, actx);
    GNUNET_free (actx);
    return;
  }
  GNUNET_SERVER_transmit_context_append_data (actx->tc, buf, strlen (buf) + 1,
                                              GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
}
/**
 * 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);
}
/**
 * Function called once the hash computation over an
 * indexed file has completed.
 *
 * @param cls closure, our publishing context
 * @param res resulting hash, NULL on error
 */
static void
hash_for_index_val (void *cls, const struct GNUNET_HashCode * res)
{
  struct IndexInfo *ii = cls;

  ii->fhc = NULL;
  if ((res == NULL) ||
      (0 != memcmp (res, &ii->file_id, sizeof (struct GNUNET_HashCode))))
  {
    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                _
                ("Hash mismatch trying to index file `%s' which has hash `%s'\n"),
                ii->filename, GNUNET_h2s (res));
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Wanted `%s'\n",
                GNUNET_h2s (&ii->file_id));
    GNUNET_SERVER_transmit_context_append_data (ii->tc, NULL, 0,
                                                GNUNET_MESSAGE_TYPE_FS_INDEX_START_FAILED);
    GNUNET_SERVER_transmit_context_run (ii->tc, GNUNET_TIME_UNIT_MINUTES);
    GNUNET_free (ii);
    return;
  }
  signal_index_ok (ii);
}
Example #10
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);
}
/**
 * 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);
}