/*
This file is part of GNUnet.
- (C) 2013 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2013 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
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.
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
*/
/**
* Handle for DHT searches.
*/
-struct GMD_search_handle
+struct GCD_search_handle
{
- /** DHT_GET handle. */
+ /**
+ * DHT_GET handle.
+ */
struct GNUNET_DHT_GetHandle *dhtget;
- /** Provided callback to call when a path is found. */
- GMD_search_callback callback;
+ /**
+ * Provided callback to call when a path is found.
+ */
+ GCD_search_callback callback;
- /** Provided closure. */
+ /**
+ * Provided closure.
+ */
void *cls;
- /** Peer ID searched for */
+ /**
+ * Peer ID searched for
+ */
GNUNET_PEER_Id peer_id;
};
/**
* Task to periodically announce itself in the network.
*/
-static GNUNET_SCHEDULER_TaskIdentifier announce_id_task;
+static struct GNUNET_SCHEDULER_Task * announce_id_task;
+
+/**
+ * Delay for the next ID announce.
+ */
+static struct GNUNET_TIME_Relative announce_delay;
/**
* GET requests to stop on shutdown.
const struct GNUNET_PeerIdentity *put_path,
unsigned int put_path_length)
{
+ size_t size = get_path_length + put_path_length + 1;
+ struct GNUNET_PeerIdentity peers[size];
+ const struct GNUNET_PeerIdentity *peer;
struct CadetPeerPath *p;
- GNUNET_PEER_Id id;
+ unsigned int own_pos;
int i;
- p = path_new (1);
- p->peers[0] = myid;
- GNUNET_PEER_change_rc (myid, 1);
- i = get_path_length;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " GET has %d hops.\n", i);
- for (i--; i >= 0; i--)
+ peers[0] = my_full_id;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " GET has %d hops.\n", get_path_length);
+ for (i = 0 ; i < get_path_length; i++)
{
- id = GNUNET_PEER_intern (&get_path[i]);
- if (p->length > 0 && id == p->peers[p->length - 1])
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Optimizing 1 hop out.\n");
- GNUNET_PEER_change_rc (id, -1);
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Adding from GET: %s.\n",
- GNUNET_i2s (&get_path[i]));
- p->length++;
- p->peers = GNUNET_realloc (p->peers, sizeof (GNUNET_PEER_Id) * p->length);
- p->peers[p->length - 1] = id;
- }
+ peer = &get_path[get_path_length - i - 1];
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " From GET: %s\n", GNUNET_i2s (peer));
+ peers[i + 1] = *peer;
}
- i = put_path_length;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " PUT has %d hops.\n", i);
- for (i--; i >= 0; i--)
+ for (i = 0 ; i < put_path_length; i++)
{
- id = GNUNET_PEER_intern (&put_path[i]);
- if (id == myid)
- {
- /* PUT path went through us, so discard the path up until now and start
- * from here to get a much shorter (and loop-free) path.
- */
- path_destroy (p);
- p = path_new (0);
- }
- if (p->length > 0 && id == p->peers[p->length - 1])
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Optimizing 1 hop out.\n");
- GNUNET_PEER_change_rc (id, -1);
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Adding from PUT: %s.\n",
- GNUNET_i2s (&put_path[i]));
- p->length++;
- p->peers = GNUNET_realloc (p->peers, sizeof (GNUNET_PEER_Id) * p->length);
- p->peers[p->length - 1] = id;
- }
+ peer = &put_path[put_path_length - i - 1];
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " From PUT: %s\n", GNUNET_i2s (peer));
+ peers[i + get_path_length + 1] = *peer;
}
-#if CADET_DEBUG
- if (get_path_length > 0)
- LOG (GNUNET_ERROR_TYPE_DEBUG, " (first of GET: %s)\n",
- GNUNET_i2s (&get_path[0]));
- if (put_path_length > 0)
- LOG (GNUNET_ERROR_TYPE_DEBUG, " (first of PUT: %s)\n",
- GNUNET_i2s (&put_path[0]));
- LOG (GNUNET_ERROR_TYPE_DEBUG, " In total: %d hops\n",
- p->length);
- for (i = 0; i < p->length; i++)
- {
- struct GNUNET_PeerIdentity peer_id;
-
- GNUNET_PEER_resolve (p->peers[i], &peer_id);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " %u: %s\n", p->peers[i],
- GNUNET_i2s (&peer_id));
- }
-#endif
+ p = path_build_from_peer_ids (peers, size, myid, &own_pos);
return p;
}
* @param exp when will this value expire
* @param key key of the result
* @param get_path path of the get request
- * @param get_path_length lenght of get_path
+ * @param get_path_length lenght of @a get_path
* @param put_path path of the put request
- * @param put_path_length length of the put_path
+ * @param put_path_length length of the @a put_path
* @param type type of the result
* @param size number of bytes in data
* @param data pointer to the result data
unsigned int put_path_length, enum GNUNET_BLOCK_Type type,
size_t size, const void *data)
{
- struct GMD_search_handle *h = cls;
+ struct GCD_search_handle *h = cls;
struct GNUNET_HELLO_Message *hello;
struct CadetPeerPath *p;
struct CadetPeer *peer;
p = path_build_from_dht (get_path, get_path_length,
put_path, put_path_length);
+ if (NULL == p)
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+
s = path_2s (p);
- LOG (GNUNET_ERROR_TYPE_INFO, "Got path from DHT: %s\n", s);
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "Got path from DHT: %s\n",
+ s);
GNUNET_free_non_null (s);
- peer = GMP_get_short (p->peers[p->length - 1]);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Got HELLO for %s\n", GMP_2s (peer));
+
+ peer = GCP_get_short (p->peers[p->length - 1], GNUNET_YES);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Got HELLO for %s\n",
+ GCP_2s (peer));
h->callback (h->cls, p);
path_destroy (p);
hello = (struct GNUNET_HELLO_Message *) data;
- GMP_set_hello (peer, hello);
- GMP_try_connect (peer);
- return;
+ GCP_set_hello (peer, hello);
+ GCP_try_connect (peer);
}
* Periodically announce self id in the DHT
*
* @param cls closure
- * @param tc task context
*/
static void
-announce_id (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+announce_id (void *cls)
{
struct GNUNET_HashCode phash;
const struct GNUNET_HELLO_Message *hello;
size_t size;
struct GNUNET_TIME_Absolute expiration;
- struct GNUNET_TIME_Relative retry_time;
+ struct GNUNET_TIME_Relative next_put;
- if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ announce_id_task = NULL;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Announce ID\n");
+ hello = GCH_get_mine ();
+ size = (NULL != hello) ? GNUNET_HELLO_size (hello) : 0;
+ if ( (NULL == hello) || (0 == size) )
{
- announce_id_task = GNUNET_SCHEDULER_NO_TASK;
- return;
+ /* Peerinfo gave us no hello yet, try again soon. */
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ " no hello, waiting!\n");
+ GNUNET_STATISTICS_update (stats,
+ "# DHT announce skipped (no hello)",
+ 1,
+ GNUNET_NO);
+ expiration = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
+ announce_delay);
+ announce_delay = GNUNET_TIME_STD_BACKOFF (announce_delay);
}
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Announce ID\n");
-
- /* TODO
- * - Set data expiration in function of X
- * - Adapt X to churn
- */
- hello = GMH_get_mine ();
- if (NULL == hello || (size = GNUNET_HELLO_size (hello)) == 0)
+ else
{
- /* Peerinfo gave us no hello yet, try again in a second. */
- announce_id_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
- &announce_id, cls);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " no hello, waiting!\n");
- return;
+ expiration = GNUNET_HELLO_get_last_expiration (hello);
+ announce_delay = GNUNET_TIME_UNIT_SECONDS;
}
- expiration = GNUNET_HELLO_get_last_expiration (hello);
- retry_time = GNUNET_TIME_absolute_get_remaining (expiration);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Hello %p size: %u\n", hello, size);
- memset (&phash, 0, sizeof (phash));
- memcpy (&phash, &my_full_id, sizeof (my_full_id));
- GNUNET_DHT_put (dht_handle, /* DHT handle */
- &phash, /* Key to use */
- dht_replication_level, /* Replication level */
- GNUNET_DHT_RO_RECORD_ROUTE
- | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, /* DHT options */
- GNUNET_BLOCK_TYPE_DHT_HELLO, /* Block type */
- size, /* Size of the data */
- (const char *) hello, /* Data itself */
- expiration, /* Data expiration */
- retry_time, /* Retry time */
- NULL, /* Continuation */
- NULL); /* Continuation closure */
- announce_id_task =
- GNUNET_SCHEDULER_add_delayed (id_announce_time, &announce_id, cls);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Hello %p size: %u\n",
+ hello,
+ size);
+ if (NULL != hello)
+ {
+ GNUNET_STATISTICS_update (stats,
+ "# DHT announce",
+ 1, GNUNET_NO);
+ memset (&phash,
+ 0,
+ sizeof (phash));
+ GNUNET_memcpy (&phash,
+ &my_full_id,
+ sizeof (my_full_id));
+ GNUNET_DHT_put (dht_handle, /* DHT handle */
+ &phash, /* Key to use */
+ dht_replication_level, /* Replication level */
+ GNUNET_DHT_RO_RECORD_ROUTE
+ | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, /* DHT options */
+ GNUNET_BLOCK_TYPE_DHT_HELLO, /* Block type */
+ size, /* Size of the data */
+ (const char *) hello, /* Data itself */
+ expiration, /* Data expiration */
+ NULL, /* Continuation */
+ NULL); /* Continuation closure */
+ }
+ /* Call again in id_announce_time, unless HELLO expires first,
+ * but wait at least 1s. */
+ next_put = GNUNET_TIME_absolute_get_remaining (expiration);
+ next_put = GNUNET_TIME_relative_min (next_put,
+ id_announce_time);
+ next_put = GNUNET_TIME_relative_max (next_put,
+ GNUNET_TIME_UNIT_SECONDS);
+ announce_id_task = GNUNET_SCHEDULER_add_delayed (next_put,
+ &announce_id,
+ cls);
}
/**
*
* @param cls Closure (unused)
* @param key Current peer ID.
- * @param value Value in the hash map (GMD_search_handle).
+ * @param value Value in the hash map (GCD_search_handle).
*
* @return #GNUNET_YES, we should continue to iterate,
*/
uint32_t key,
void *value)
{
- struct GMD_search_handle *h = value;
+ struct GCD_search_handle *h = value;
- GMD_search_stop (h);
+ GCD_search_stop (h);
return GNUNET_YES;
}
* @param c Configuration.
*/
void
-GMD_init (const struct GNUNET_CONFIGURATION_Handle *c)
+GCD_init (const struct GNUNET_CONFIGURATION_Handle *c)
{
LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (c, "CADET", "DHT_REPLICATION_LEVEL",
+ GNUNET_CONFIGURATION_get_value_number (c, "CADET",
+ "DHT_REPLICATION_LEVEL",
&dht_replication_level))
{
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
- "CADET", "DHT_REPLICATION_LEVEL", "USING DEFAULT");
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, "CADET",
+ "DHT_REPLICATION_LEVEL", "USING DEFAULT");
dht_replication_level = 3;
}
GNUNET_CONFIGURATION_get_value_time (c, "CADET", "ID_ANNOUNCE_TIME",
&id_announce_time))
{
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
- "CADET", "ID_ANNOUNCE_TIME", "MISSING");
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "CADET",
+ "ID_ANNOUNCE_TIME", "MISSING");
GNUNET_SCHEDULER_shutdown ();
return;
}
GNUNET_break (0);
}
+ announce_delay = GNUNET_TIME_UNIT_SECONDS;
announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, NULL);
get_requests = GNUNET_CONTAINER_multihashmap32_create (32);
}
* Shut down the DHT subsystem.
*/
void
-GMD_shutdown (void)
+GCD_shutdown (void)
{
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down DHT\n");
GNUNET_CONTAINER_multihashmap32_iterate (get_requests, &stop_get, NULL);
GNUNET_CONTAINER_multihashmap32_destroy (get_requests);
if (dht_handle != NULL)
GNUNET_DHT_disconnect (dht_handle);
dht_handle = NULL;
}
- if (GNUNET_SCHEDULER_NO_TASK != announce_id_task)
+ if (NULL != announce_id_task)
{
GNUNET_SCHEDULER_cancel (announce_id_task);
- announce_id_task = GNUNET_SCHEDULER_NO_TASK;
+ announce_id_task = NULL;
}
}
-struct GMD_search_handle *
-GMD_search (const struct GNUNET_PeerIdentity *peer_id,
- GMD_search_callback callback, void *cls)
+struct GCD_search_handle *
+GCD_search (const struct GNUNET_PeerIdentity *peer_id,
+ GCD_search_callback callback, void *cls)
{
struct GNUNET_HashCode phash;
- struct GMD_search_handle *h;
+ struct GCD_search_handle *h;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " Starting DHT GET for peer %s\n", GNUNET_i2s (peer_id));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting DHT GET for peer %s\n",
+ GNUNET_i2s (peer_id));
+ GNUNET_STATISTICS_update (stats, "# DHT search", 1, GNUNET_NO);
memset (&phash, 0, sizeof (phash));
- memcpy (&phash, peer_id, sizeof (*peer_id));
- h = GNUNET_new (struct GMD_search_handle);
+ GNUNET_memcpy (&phash, peer_id, sizeof (*peer_id));
+ h = GNUNET_new (struct GCD_search_handle);
h->peer_id = GNUNET_PEER_intern (peer_id);
h->callback = callback;
h->cls = cls;
GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
NULL, /* xquery */
0, /* xquery bits */
- &dht_get_id_handler, h);
- GNUNET_CONTAINER_multihashmap32_put (get_requests, h->peer_id, h,
+ &dht_get_id_handler,
+ h);
+ GNUNET_CONTAINER_multihashmap32_put (get_requests,
+ h->peer_id,
+ h,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
return h;
}
+
void
-GMD_search_stop (struct GMD_search_handle *h)
+GCD_search_stop (struct GCD_search_handle *h)
{
GNUNET_break (GNUNET_OK ==
GNUNET_CONTAINER_multihashmap32_remove (get_requests,