$(XLIB)
libgnunet_plugin_dhtlog_mysql_dump_la_LDFLAGS = \
$(GN_PLUGIN_LDFLAGS)
-
+
libgnunet_plugin_dhtlog_mysql_dump_load_la_SOURCES = \
plugin_dhtlog_mysql_dump_load.c
libgnunet_plugin_dhtlog_mysql_dump_load_la_LIBADD = \
$(GN_LIB_LDFLAGS) $(WINFLAGS) \
-version-info 0:0:0
+libgnunetdht_la_SOURCES = \
libgnunetdht_la_SOURCES = \
dht_api.c dht.h \
dht_api_get_put.c \
gnunet-service-dht \
gnunet-dht-get \
gnunet-dht-get-peer \
- gnunet-dht-put
+ gnunet-dht-put \
+ gnunet-dht-driver
-if HAVE_MALICIOUS
-noinst_PROGRAMS = \
- gnunet-dht-driver
-endif
+noinst_PROGRAMS = $(check_PROGRAMS)
gnunet_service_dht_SOURCES = \
gnunet-service-dht.c
test_dht_api \
test_dht_twopeer \
test_dht_twopeer_put_get \
+ test_dht_twopeer_path_tracking \
test_dht_multipeer \
- test_dhtlog
-# test_hash_operations
+ test_dhtlog
if !DISABLE_TEST_RUN
TESTS = test_dht_api $(check_SCRIPTS) \
test_dht_twopeer \
- test_dht_twopeer_put_get
+ test_dht_twopeer_put_get \
+ test_dht_twopeer_path_tracking \
+ test_dht_multipeer \
+ test_dhtlog
endif
test_dht_api_SOURCES = \
test_dht_multipeer_DEPENDENCIES = \
libgnunetdht.la
-#test_hash_operations_SOURCES = \
-# test_hash_operations.c
-#test_hash_operations_LDADD = \
-# $(top_builddir)/src/util/libgnunetutil.la \
-# $(top_builddir)/src/testing/libgnunettesting.la \
-# $(top_builddir)/src/dht/libgnunetdht.la
-
test_dht_twopeer_SOURCES = \
test_dht_twopeer.c
test_dht_twopeer_LDADD = \
$(top_builddir)/src/util/libgnunetutil.la \
$(top_builddir)/src/testing/libgnunettesting.la \
$(top_builddir)/src/dht/libgnunetdht.la
+
+test_dht_twopeer_path_tracking_SOURCES = \
+ test_dht_twopeer_path_tracking.c
+test_dht_twopeer_path_tracking_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/testing/libgnunettesting.la \
+ $(top_builddir)/src/dht/libgnunetdht.la
test_dhtlog_SOURCES = \
test_dhtlog.c
struct GNUNET_MessageHeader header;
/**
- * Number of peers recorded in the "PUT" path.
- * (original path message took during "PUT"). These
- * peer identities follow this message.
+ * Number of peers recorded in the outgoing
+ * path from source to the final destination
+ * of this message.
*/
- uint16_t put_path_length GNUNET_PACKED;
-
- /**
- * Number of peers recorded in the "GET" path
- * (inverse of the path the GET message took). These
- * peer identities follow this message.
- */
- uint16_t get_path_length GNUNET_PACKED;
+ uint32_t outgoing_path_length GNUNET_PACKED;
/**
* Unique ID identifying this request (necessary for
*/
GNUNET_HashCode key;
- /* PUT path */
-
- /* GET path */
-
/* GNUNET_MessageHeader *enc actual DHT message, copied to end of this dealy do */
+
+ /* OUTGOING path */
};
uint32_t network_size GNUNET_PACKED;
/**
- * Route path length; number of GNUNET_PeerIdentity's
- * copied to the end of this message (before the actual
- * encapsulated message)
+ * Generic route path length for a message in the
+ * DHT that arrived at a peer and generated
+ * a reply. Copied to the end of this message.
*/
- uint32_t route_path_length GNUNET_PACKED;
+ uint32_t outgoing_path_length GNUNET_PACKED;
/**
* Unique ID identifying this request
/* GNUNET_MessageHeader *enc actual DHT message, copied to end of this dealy do */
+ /* OUTGOING PATH */
+
};
/**
* (inverse of the path the outgoing message took).
* These peer identities follow this message.
*/
- uint16_t outgoing_path_length GNUNET_PACKED;
+ uint32_t outgoing_path_length GNUNET_PACKED;
/**
* Message options
uint32_t network_size GNUNET_PACKED;
#endif
-
- /* PUT path */
-
- /* GET path */
-
/* GNUNET_MessageHeader *enc actual DHT message, copied to end of this dealy do */
+
+ /* OUTGOING PATH */
};
/**
* The type for the data for the GET request
*/
- uint32_t type;
+ uint16_t type;
+
+ /**
+ * The number of peer identities appended to the end of this
+ * message.
+ */
+ uint16_t put_path_length;
/**
* When does this entry expire?
};
+/**
+ * Entry for inserting data into datacache from the DHT.
+ * Needed here so block library can verify entries that
+ * are shoveled into the DHT.
+ */
+struct DHTPutEntry
+{
+ /**
+ * Size of data.
+ */
+ uint16_t data_size;
+
+ /**
+ * Length of recorded path.
+ */
+ uint16_t path_length;
+
+ /* PUT DATA */
+
+ /* PATH ENTRIES */
+};
+
#endif /* DHT_H_ */
*/
struct GNUNET_CONTAINER_MultiHashMap *active_requests;
+ /**
+ * Task for trying to reconnect.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
+
+ /**
+ * How quickly should we retry? Used for exponential back-off on
+ * connect-errors.
+ */
+ struct GNUNET_TIME_Relative retry_time;
+
/**
* Generator for unique ids.
*/
/**
- * Re-connect to the DHT, re-issue all pending requests if needed.
+ * Try reconnecting to the dht service.
+ *
+ * @param cls GNUNET_DHT_Handle
+ * @param tc scheduler context
*/
static void
-reconnect (struct GNUNET_DHT_Handle *handle)
+try_reconnect (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
{
- if (handle->client != NULL)
+ struct GNUNET_DHT_Handle *handle = cls;
+
+ if (handle->retry_time.rel_value < GNUNET_CONSTANTS_SERVICE_RETRY.rel_value)
+ handle->retry_time = GNUNET_CONSTANTS_SERVICE_RETRY;
+ else
+ handle->retry_time = GNUNET_TIME_relative_multiply (handle->retry_time, 2);
+ if (handle->retry_time.rel_value > GNUNET_CONSTANTS_SERVICE_TIMEOUT.rel_value)
+ handle->retry_time = GNUNET_CONSTANTS_SERVICE_TIMEOUT;
+ handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
+ handle->client = GNUNET_CLIENT_connect ("dht", handle->cfg);
+ if (handle->client == NULL)
{
- GNUNET_CLIENT_disconnect (handle->client,
- GNUNET_NO);
- handle->client = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "dht reconnect failed(!)\n");
+ return;
}
- if (GNUNET_YES != try_connect (handle))
- return;
+
GNUNET_CONTAINER_multihashmap_iterate (handle->active_requests,
- &add_request_to_pending,
- handle);
+ &add_request_to_pending,
+ handle);
if (handle->pending_head == NULL)
return;
GNUNET_CLIENT_notify_transmit_ready (handle->client,
- ntohs(handle->pending_head->msg->size),
- GNUNET_TIME_UNIT_FOREVER_REL,
- GNUNET_NO,
- &transmit_pending,
- handle);
-
+ ntohs(handle->pending_head->msg->size),
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_NO,
+ &transmit_pending,
+ handle);
+}
+
+
+/**
+ * Try reconnecting to the DHT service.
+ *
+ * @param handle handle to dht to (possibly) disconnect and reconnect
+ */
+static void
+do_disconnect (struct GNUNET_DHT_Handle *handle)
+{
+ if (handle->client == NULL)
+ return;
+
+ GNUNET_CLIENT_disconnect (handle->client, GNUNET_NO);
+ handle->client = NULL;
+ handle->reconnect_task = GNUNET_SCHEDULER_add_delayed (handle->retry_time,
+ &try_reconnect,
+ handle);
}
{
struct PendingMessage *head;
- if (GNUNET_YES != try_connect (handle))
- return;
+ if (handle->client == NULL)
+ {
+ do_disconnect(handle);
+ return;
+ }
if (handle->th != NULL)
return;
if (NULL == (head = handle->pending_head))
handle);
if (NULL == handle->th)
{
- reconnect (handle);
+ do_disconnect (handle);
return;
}
}
handle->th = NULL;
if (buf == NULL)
{
- reconnect (handle);
+ do_disconnect (handle);
return 0;
}
if (NULL == (head = handle->pending_head))
}
-
-
/**
* Process a given reply that might match the given
* request.
const struct GNUNET_MessageHeader *enc_msg;
size_t enc_size;
uint64_t uid;
- const struct GNUNET_PeerIdentity **get_path;
- const struct GNUNET_PeerIdentity **put_path;
+ const struct GNUNET_PeerIdentity **outgoing_path;
const struct GNUNET_PeerIdentity *pos;
- uint16_t gpl;
- uint16_t ppl;
+ uint32_t outgoing_path_length;
unsigned int i;
+ char *path_offset;
uid = GNUNET_ntohll (dht_msg->unique_id);
if (uid != rh->uid)
"Reply UID did not match request UID\n");
return GNUNET_YES;
}
- enc_size = ntohs (dht_msg->header.size) - sizeof (struct GNUNET_DHT_RouteResultMessage);
+ enc_msg = (const struct GNUNET_MessageHeader *)&dht_msg[1];
+ enc_size = ntohs (enc_msg->size);
if (enc_size < sizeof (struct GNUNET_MessageHeader))
{
GNUNET_break (0);
return GNUNET_NO;
}
- pos = (const struct GNUNET_PeerIdentity *) &dht_msg[1];
- ppl = ntohs (dht_msg->put_path_length);
- gpl = ntohs (dht_msg->get_path_length);
- if ( (ppl + gpl) * sizeof (struct GNUNET_PeerIdentity) > enc_size)
+ path_offset = (char *)&dht_msg[1];
+ path_offset += enc_size;
+ pos = (const struct GNUNET_PeerIdentity *) path_offset;
+ outgoing_path_length = ntohl (dht_msg->outgoing_path_length);
+ if (outgoing_path_length * sizeof (struct GNUNET_PeerIdentity) > ntohs(dht_msg->header.size) - enc_size)
{
GNUNET_break (0);
return GNUNET_NO;
}
- if (ppl > 0)
- {
- put_path = GNUNET_malloc ((ppl+1) * sizeof (struct GNUNET_PeerIdentity*));
- for (i=0;i<ppl;i++)
- {
- put_path[i] = pos;
- pos++;
- }
- put_path[ppl] = NULL;
- }
- else
- put_path = NULL;
- if (gpl > 0)
+
+ if (outgoing_path_length > 0)
{
- get_path = GNUNET_malloc ((gpl+1) * sizeof (struct GNUNET_PeerIdentity*));
- for (i=0;i<gpl;i++)
+ outgoing_path = GNUNET_malloc ((outgoing_path_length + 1) * sizeof (struct GNUNET_PeerIdentity*));
+ for (i = 0; i < outgoing_path_length; i++)
{
- get_path[i] = pos;
+ outgoing_path[i] = pos;
pos++;
}
- get_path[gpl] = NULL;
+ outgoing_path[outgoing_path_length] = NULL;
}
else
- get_path = NULL;
- enc_size -= (ppl + gpl) * sizeof (struct GNUNET_PeerIdentity);
- enc_msg = (const struct GNUNET_MessageHeader *) pos;
- if (enc_size != ntohs (enc_msg->size))
- {
- GNUNET_break (0);
- GNUNET_free_non_null (get_path);
- GNUNET_free_non_null (put_path);
- return GNUNET_NO;
- }
+ outgoing_path = NULL;
+
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Processing reply.\n");
rh->iter (rh->iter_cls,
&rh->key,
- get_path,
- put_path,
+ outgoing_path,
enc_msg);
- GNUNET_free_non_null (get_path);
- GNUNET_free_non_null (put_path);
+ GNUNET_free_non_null (outgoing_path);
return GNUNET_YES;
}
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Error receiving data from DHT service, reconnecting\n");
- reconnect (handle);
+ do_disconnect (handle);
return;
}
if (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_DHT_LOCAL_ROUTE_RESULT)
{
GNUNET_break (0);
- reconnect (handle);
+ do_disconnect (handle);
return;
}
if (ntohs (msg->size) < sizeof (struct GNUNET_DHT_RouteResultMessage))
{
GNUNET_break (0);
- reconnect (handle);
+ do_disconnect (handle);
return;
}
dht_msg = (const struct GNUNET_DHT_RouteResultMessage *) msg;
*
* @param cls closure
* @param key key that was used
- * @param get_path NULL-terminated array of pointers
- * to the peers on reverse GET path (or NULL if not recorded)
- * @param put_path NULL-terminated array of pointers
- * to the peers on the PUT path (or NULL if not recorded)
+ * @param outgoing_path NULL-terminated array of pointers
+ * to the peers on reverse path
+ * (or NULL if not recorded)
* @param reply response
*/
static void
find_peer_reply_iterator (void *cls,
const GNUNET_HashCode *key,
- const struct GNUNET_PeerIdentity * const *get_path,
- const struct GNUNET_PeerIdentity * const *put_path,
+ const struct GNUNET_PeerIdentity * const *outgoing_path,
const struct GNUNET_MessageHeader *reply)
{
struct GNUNET_DHT_FindPeerHandle *find_peer_handle = cls;
*
* @param cls the 'struct GNUNET_DHT_GetHandle'
* @param key key that was used
- * @param get_path NULL-terminated array of pointers
- * to the peers on reverse GET path (or NULL if not recorded)
- * @param put_path NULL-terminated array of pointers
- * to the peers on the PUT path (or NULL if not recorded)
+ * @param outgoing_path path of the message from this peer
+ * to the target
* @param reply response
*/
static void
get_reply_iterator (void *cls,
const GNUNET_HashCode *key,
- const struct GNUNET_PeerIdentity * const *get_path,
- const struct GNUNET_PeerIdentity * const *put_path,
+ const struct GNUNET_PeerIdentity * const *outgoing_path,
const struct GNUNET_MessageHeader *reply)
{
struct GNUNET_DHT_GetHandle *get_handle = cls;
const struct GNUNET_DHT_GetResultMessage *result;
+ const struct GNUNET_PeerIdentity **put_path;
size_t payload;
+ char *path_offset;
+ const struct GNUNET_PeerIdentity *pos;
+ unsigned int i;
+ uint16_t put_path_length;
+ uint16_t data_size;
if (ntohs (reply->type) != GNUNET_MESSAGE_TYPE_DHT_GET_RESULT)
{
GNUNET_assert (ntohs (reply->size) >=
sizeof (struct GNUNET_DHT_GetResultMessage));
result = (const struct GNUNET_DHT_GetResultMessage *) reply;
+
+ put_path = NULL;
+ put_path_length = ntohs(result->put_path_length);
+ if (put_path_length > 0)
+ {
+ data_size = ntohs(result->header.size) - (put_path_length * sizeof(struct GNUNET_PeerIdentity)) - sizeof(struct GNUNET_DHT_GetResultMessage);
+ path_offset = (char *)&result[1];
+ //GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "In get_reply_iterator, result->header.size is %d, put_path_length %d, offset is %d, data_size is %d\n", ntohs(result->header.size), put_path_length, ntohs(result->header.size) - (put_path_length * sizeof(struct GNUNET_PeerIdentity)), data_size);
+ path_offset += data_size;
+ pos = (const struct GNUNET_PeerIdentity *)path_offset;
+ //GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Found put peer %s\n", GNUNET_i2s((const struct GNUNET_PeerIdentity *)path_offset));
+ put_path = GNUNET_malloc ((put_path_length + 1) * sizeof (struct GNUNET_PeerIdentity*));
+ for (i = 0; i < put_path_length; i++)
+ {
+ put_path[i] = pos;
+ pos++;
+ }
+ put_path[put_path_length] = NULL;
+ }
+
payload = ntohs (reply->size) - sizeof(struct GNUNET_DHT_GetResultMessage);
get_handle->iter (get_handle->iter_cls,
GNUNET_TIME_absolute_ntoh (result->expiration),
key,
- get_path,
+ outgoing_path,
put_path,
ntohs (result->type),
payload,
&result[1]);
+ GNUNET_free_non_null(put_path);
}
size_t msize;
size_t psize;
char *path_start;
+ char *path_offset;
+#if DEBUG_PATH
+ unsigned int i;
+#endif
increment_stats (STAT_RESULT_FORWARDS);
msize =
/* Offset by the size of the enc_msg */
path_start += ntohs (msg->size);
memcpy(path_start, msg_ctx->path_history, msg_ctx->path_history_len * (sizeof(struct GNUNET_PeerIdentity)));
+#if DEBUG_PATH
+ for (i = 0; i < msg_ctx->path_history_len; i++)
+ {
+ path_offset = &msg_ctx->path_history[i * sizeof(struct GNUNET_PeerIdentity)];
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "(forward_result) Key %s Found peer %d:%s\n", GNUNET_h2s(&msg_ctx->key), i, GNUNET_i2s((struct GNUNET_PeerIdentity *)path_offset));
+ }
+#endif
}
result_message->options = htonl (msg_ctx->msg_options);
result_message->hop_count = htonl (msg_ctx->hop_count + 1);
DHT_BLOOM_SIZE));
result_message->unique_id = GNUNET_htonll (msg_ctx->unique_id);
memcpy (&result_message->key, &msg_ctx->key, sizeof (GNUNET_HashCode));
+ /* Copy the enc_msg, then the path history as well! */
memcpy (&result_message[1], msg, ntohs (msg->size));
+ path_offset = (char *)&result_message[1];
+ path_offset += ntohs (msg->size);
+ /* If we have path history, copy it to the end of the whole thing */
+ if (msg_ctx->path_history_len > 0)
+ memcpy(path_offset, msg_ctx->path_history, msg_ctx->path_history_len * (sizeof(struct GNUNET_PeerIdentity)));
#if DEBUG_DHT > 1
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"%s:%s Adding pending message size %d for peer %s\n",
memcpy (&route_message[1], msg, ntohs (msg->size));
if (GNUNET_DHT_RO_RECORD_ROUTE == (msg_ctx->msg_options & GNUNET_DHT_RO_RECORD_ROUTE))
{
- route_message->route_path_length = htonl(msg_ctx->path_history_len);
+ route_message->outgoing_path_length = htonl(msg_ctx->path_history_len);
/* Set pointer to start of enc_msg */
route_path = (char *)&route_message[1];
/* Offset to the end of the enc_msg */
static void
send_reply_to_client (struct ClientList *client,
const struct GNUNET_MessageHeader *message,
- unsigned long long uid, const GNUNET_HashCode * key)
+ struct DHT_MessageContext *msg_ctx)
{
struct GNUNET_DHT_RouteResultMessage *reply;
struct PendingMessage *pending_message;
uint16_t msize;
size_t tsize;
+ char *reply_offset;
+#if DEBUG_PATH
+ char *path_offset;
+ unsigned int i;
+#endif
#if DEBUG_DHT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"`%s:%s': Sending reply to client.\n", my_short_id, "DHT");
#endif
msize = ntohs (message->size);
- tsize = sizeof (struct GNUNET_DHT_RouteResultMessage) + msize;
+ tsize = sizeof (struct GNUNET_DHT_RouteResultMessage) + msize + (msg_ctx->path_history_len * sizeof(struct GNUNET_PeerIdentity));
if (tsize >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
{
GNUNET_break_op (0);
reply = (struct GNUNET_DHT_RouteResultMessage *) &pending_message[1];
reply->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_LOCAL_ROUTE_RESULT);
reply->header.size = htons (tsize);
- reply->put_path_length = htons (0); /* FIXME: implement */
- reply->get_path_length = htons (0); /* FIXME: implement */
- reply->unique_id = GNUNET_htonll (uid);
- reply->key = *key;
+ reply->outgoing_path_length = htonl(msg_ctx->path_history_len);
+ reply->unique_id = GNUNET_htonll (msg_ctx->unique_id);
+ memcpy (&reply->key, &msg_ctx->key, sizeof (GNUNET_HashCode));
+ reply_offset = (char *)&reply[1];
memcpy (&reply[1], message, msize);
+ if (msg_ctx->path_history_len > 0)
+ {
+ reply_offset += msize;
+ memcpy(reply_offset, msg_ctx->path_history, msg_ctx->path_history_len * sizeof(struct GNUNET_PeerIdentity));
+ }
+#if DEBUG_PATH
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Returning message with outgoing path length %d\n", msg_ctx->path_history_len);
+ for (i = 0; i < msg_ctx->path_history_len; i++)
+ {
+ path_offset = &msg_ctx->path_history[i * sizeof(struct GNUNET_PeerIdentity)];
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Found peer %d:%s\n", i, GNUNET_i2s((struct GNUNET_PeerIdentity *)path_offset));
+ }
+#endif
add_pending_message (client, pending_message);
}
struct DHTRouteSource *pos;
struct PeerInfo *peer_info;
const struct GNUNET_MessageHeader *hello_msg;
+ unsigned int i;
+ char *path_offset;
increment_stats (STAT_RESULTS);
/**
if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_DHT_GET_RESULT)
increment_stats (STAT_GET_REPLY);
- send_reply_to_client (pos->client, msg,
- msg_ctx->unique_id, &msg_ctx->key);
+ for (i = 0; i < msg_ctx->path_history_len; i++)
+ {
+ path_offset = &msg_ctx->path_history[i * sizeof(struct GNUNET_PeerIdentity)];
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "(before client) Key %s Found peer %d:%s\n", GNUNET_h2s(&msg_ctx->key), i, GNUNET_i2s((struct GNUNET_PeerIdentity *)path_offset));
+ }
+ send_reply_to_client (pos->client, msg, msg_ctx);
}
else /* Send to peer */
{
struct DHT_MessageContext *new_msg_ctx;
struct GNUNET_DHT_GetResultMessage *get_result;
enum GNUNET_BLOCK_EvaluationResult eval;
+ const struct DHTPutEntry *put_entry;
+ int get_size;
+ char *path_offset;
+#if DEBUG_PATH
+ unsigned int i;
+#endif
#if DEBUG_DHT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
msg_ctx->reply_bf_mutator,
msg_ctx->xquery,
msg_ctx->xquery_size, data, size);
+
+ put_entry = (const struct DHTPutEntry *)data;
+
+ if (size != sizeof(struct DHTPutEntry) +
+ put_entry->data_size +
+ (put_entry->path_length * sizeof(struct GNUNET_PeerIdentity)))
+ {
+ GNUNET_log(
+ GNUNET_ERROR_TYPE_WARNING,
+ "Path + data size doesn't add up for data inserted into datacache!\nData size %d, path length %d, expected %d, got %d\n",
+ put_entry->data_size, put_entry->path_length,
+ sizeof(struct DHTPutEntry) + put_entry->data_size
+ + (put_entry->path_length * sizeof(struct GNUNET_PeerIdentity)),
+ size);
+ msg_ctx->do_forward = GNUNET_NO;
+ return GNUNET_OK;
+ }
+
switch (eval)
{
case GNUNET_BLOCK_EVALUATION_OK_LAST:
new_msg_ctx->path_history_len = msg_ctx->path_history_len;
/* Assign to previous msg_ctx path history, caller should free after our return */
new_msg_ctx->path_history = msg_ctx->path_history;
+#if DEBUG_PATH
+ for (i = 0; i < new_msg_ctx->path_history_len; i++)
+ {
+ path_offset = &new_msg_ctx->path_history[i * sizeof(struct GNUNET_PeerIdentity)];
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "(get_iterator) Key %s Found peer %d:%s\n", GNUNET_h2s(&msg_ctx->key), i, GNUNET_i2s((struct GNUNET_PeerIdentity *)path_offset));
+ }
+#endif
}
- get_result =
- GNUNET_malloc (sizeof (struct GNUNET_DHT_GetResultMessage) + size);
+
+ get_size = sizeof (struct GNUNET_DHT_GetResultMessage) + put_entry->data_size + (put_entry->path_length * sizeof(struct GNUNET_PeerIdentity));
+ get_result = GNUNET_malloc (get_size);
get_result->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_GET_RESULT);
- get_result->header.size =
- htons (sizeof (struct GNUNET_DHT_GetResultMessage) + size);
+ get_result->header.size = htons (get_size);
get_result->expiration = GNUNET_TIME_absolute_hton (exp);
get_result->type = htons (type);
- memcpy (&get_result[1], data, size);
+ get_result->put_path_length = htons(put_entry->path_length);
+ path_offset = (char *)&put_entry[1];
+ path_offset += put_entry->data_size;
+#if DEBUG_PATH
+ for (i = 0; i < put_entry->path_length; i++)
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "(get_iterator PUT path) Key %s Found peer %d:%s\n", GNUNET_h2s(&msg_ctx->key), i, GNUNET_i2s((struct GNUNET_PeerIdentity *)&path_offset[i * sizeof(struct GNUNET_PeerIdentity)]));
+ }
+#endif
+ /* Copy the actual data and the path_history to the end of the get result */
+ memcpy (&get_result[1], &put_entry[1], put_entry->data_size + (put_entry->path_length * sizeof(struct GNUNET_PeerIdentity)));
new_msg_ctx->peer = &my_identity;
new_msg_ctx->bloom =
GNUNET_CONTAINER_bloomfilter_init (NULL, DHT_BLOOM_SIZE, DHT_BLOOM_K);
break;
case GNUNET_BLOCK_EVALUATION_RESULT_INVALID:
#if DEBUG_DHT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"`%s:%s': Invalid request error\n", my_short_id, "DHT");
#endif
break;
break;
case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED:
#if DEBUG_DHT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"`%s:%s': Unsupported block type (%u) in response!\n",
my_short_id, "DHT", type);
#endif
struct DHT_MessageContext *msg_ctx)
{
const struct GNUNET_DHT_PutMessage *put_msg;
+ struct DHTPutEntry *put_entry;
+ unsigned int put_size;
+ char *path_offset;
enum GNUNET_BLOCK_Type put_type;
size_t data_size;
int ret;
GNUNET_assert (ntohs (msg->size) >= sizeof (struct GNUNET_DHT_PutMessage));
-
put_msg = (const struct GNUNET_DHT_PutMessage *) msg;
put_type = (enum GNUNET_BLOCK_Type) ntohl (put_msg->type);
#if HAVE_MALICIOUS
increment_stats (STAT_PUTS_INSERTED);
if (datacache != NULL)
{
- ret = GNUNET_DATACACHE_put (datacache, &msg_ctx->key, data_size,
- (char *) &put_msg[1], put_type,
+ /* Put size is actual data size plus struct overhead plus path length (if any) */
+ put_size = data_size + sizeof(struct DHTPutEntry) + (msg_ctx->path_history_len * sizeof(struct GNUNET_PeerIdentity));
+ put_entry = GNUNET_malloc(put_size);
+ put_entry->data_size = data_size;
+ put_entry->path_length = msg_ctx->path_history_len;
+ /* Copy data to end of put entry */
+ memcpy(&put_entry[1], &put_msg[1], data_size);
+ if (msg_ctx->path_history_len > 0)
+ {
+ /* Copy path after data */
+ path_offset = (char *)&put_entry[1];
+ path_offset += data_size;
+ memcpy(path_offset, msg_ctx->path_history, msg_ctx->path_history_len * sizeof(struct GNUNET_PeerIdentity));
+ }
+ ret = GNUNET_DATACACHE_put (datacache, &msg_ctx->key, put_size,
+ (char *) put_entry, put_type,
GNUNET_TIME_absolute_ntoh
(put_msg->expiration));
msg_ctx->msg_options = ntohl (incoming->options);
if (GNUNET_DHT_RO_RECORD_ROUTE == (msg_ctx->msg_options & GNUNET_DHT_RO_RECORD_ROUTE))
{
- path_size = ntohl(incoming->route_path_length) * sizeof(struct GNUNET_PeerIdentity);
+ path_size = ntohl(incoming->outgoing_path_length) * sizeof(struct GNUNET_PeerIdentity);
GNUNET_assert(ntohs(message->size) ==
(sizeof(struct GNUNET_DHT_P2PRouteMessage) +
ntohs(enc_msg->size) +
msg_ctx->path_history = GNUNET_malloc(sizeof(struct GNUNET_PeerIdentity) + path_size);
memcpy(msg_ctx->path_history, route_path, path_size);
memcpy(&msg_ctx->path_history[path_size], &my_identity, sizeof(struct GNUNET_PeerIdentity));
- msg_ctx->path_history_len = ntohl(incoming->route_path_length) + 1;
+ msg_ctx->path_history_len = ntohl(incoming->outgoing_path_length) + 1;
}
msg_ctx->network_size = ntohl (incoming->network_size);
msg_ctx->peer = peer;
struct GNUNET_MessageHeader *enc_msg =
(struct GNUNET_MessageHeader *) &incoming[1];
struct DHT_MessageContext msg_ctx;
-
+#if DEBUG_PATH
+ char *path_offset;
+ unsigned int i;
+#endif
if (ntohs (enc_msg->size) >= GNUNET_SERVER_MAX_MESSAGE_SIZE - 1)
{
GNUNET_break_op (0);
if (ntohs(message->size) - sizeof(struct GNUNET_DHT_P2PRouteResultMessage) - ntohs(enc_msg->size) !=
ntohl (incoming->outgoing_path_length) * sizeof(struct GNUNET_PeerIdentity))
{
- GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Return message indicated a path was included, but sizes are wrong!\nTotal message size %d, enc_msg size %d, left over %d, expected %d\n",
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Return message indicated a path was included, but sizes are wrong!\nTotal message size %d, enc_msg size %d, left over %d, expected %d\n",
ntohs(message->size), ntohs(enc_msg->size),
ntohs(message->size) - sizeof(struct GNUNET_DHT_P2PRouteResultMessage) - ntohs(enc_msg->size),
ntohl(incoming->outgoing_path_length) * sizeof(struct GNUNET_PeerIdentity));
return GNUNET_NO;
}
-
msg_ctx.path_history = (char *)&incoming[1];
msg_ctx.path_history += ntohs(enc_msg->size);
msg_ctx.path_history_len = ntohl (incoming->outgoing_path_length);
+#if DEBUG_PATH
+ for (i = 0; i < msg_ctx.path_history_len; i++)
+ {
+ path_offset = &msg_ctx.path_history[i * sizeof(struct GNUNET_PeerIdentity)];
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "(handle_p2p_route_result) Key %s Found peer %d:%s\n", GNUNET_h2s(&msg_ctx.key), i, GNUNET_i2s((struct GNUNET_PeerIdentity *)path_offset));
+ }
+#endif
}
route_result_message (enc_msg, &msg_ctx);
return GNUNET_YES;
const struct GNUNET_TRANSPORT_ATS_Information *atsi)
{
struct PeerInfo *ret;
-
+ struct DHTPutEntry *put_entry;
/* Check for connect to self message */
if (0 == memcmp(&my_identity, peer, sizeof(struct GNUNET_PeerIdentity)))
return;
}
if (datacache != NULL)
- GNUNET_DATACACHE_put (datacache, &peer->hashPubKey,
- sizeof (struct GNUNET_PeerIdentity),
- (const char *) peer, GNUNET_BLOCK_TYPE_DHT_HELLO,
- GNUNET_TIME_absolute_get_forever ());
+ {
+ put_entry = GNUNET_malloc(sizeof(struct DHTPutEntry) + sizeof (struct GNUNET_PeerIdentity));
+ put_entry->path_length = 0;
+ put_entry->data_size = sizeof (struct GNUNET_PeerIdentity);
+ memcpy(&put_entry[1], peer, sizeof (struct GNUNET_PeerIdentity));
+ GNUNET_DATACACHE_put (datacache, &peer->hashPubKey,
+ sizeof(struct DHTPutEntry) + sizeof (struct GNUNET_PeerIdentity),
+ (char *)put_entry, GNUNET_BLOCK_TYPE_DHT_HELLO,
+ GNUNET_TIME_absolute_get_forever ());
+ }
+ else
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "DHT has no connection to datacache!\n");
ret = try_add_peer (peer, find_current_bucket (&peer->hashPubKey), atsi);
if (ret != NULL)
{
[fs]
AUTOSTART = NO
+[resolver]
+AUTOSTART = NO
+
[datastore-sqlite]
FILENAME = $SERVICEHOME/datastore/sqlite.db
[fs]
AUTOSTART = NO
+[resolver]
+AUTOSTART = NO
+
[dht]
DEBUG = NO
AUTOSTART = YES
#define MAX_OUTSTANDING_GETS 10
+#define PATH_TRACKING GNUNET_YES
+
/* Structs */
struct TestPutContext
*/
static unsigned int failed_connections;
+enum GNUNET_DHT_RouteOption route_option;
+
/* Task handle to use to schedule test failure */
GNUNET_SCHEDULER_TaskIdentifier die_task;
/* Global return value (0 for success, anything else for failure) */
static int ok;
-
/**
* Check whether peers successfully shut down.
*/
struct TestGetContext *test_get = cls;
GNUNET_HashCode search_key; /* Key stored under */
char original_data[TEST_DATA_SIZE]; /* Made up data to store */
-
+ unsigned int i;
memset(original_data, test_get->uid, sizeof(original_data));
GNUNET_CRYPTO_hash(original_data, TEST_DATA_SIZE, &search_key);
if (test_get->succeeded == GNUNET_YES)
return; /* Get has already been successful, probably ending now */
+#if PATH_TRACKING
+ if (put_path != NULL)
+ {
+ fprintf(stderr, "PUT Path: ");
+ for (i = 0; put_path[i] != NULL; i++)
+ fprintf(stderr, "%s%s", i == 0 ? "" : "->", GNUNET_i2s(put_path[i]));
+ fprintf(stderr, "\n");
+ }
+ if (get_path != NULL)
+ {
+ fprintf(stderr, "GET Path: ");
+ for (i = 0; get_path[i] != NULL; i++)
+ fprintf(stderr, "%s%s", i == 0 ? "" : "->", GNUNET_i2s(get_path[i]));
+ fprintf(stderr, "\n");
+ }
+#endif
+
if ((0 != memcmp(&search_key, key, sizeof (GNUNET_HashCode))) || (0 != memcmp(original_data, data, sizeof(original_data))))
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Key or data is not the same as was inserted!\n");
GNUNET_BLOCK_TYPE_TEST,
&key,
DEFAULT_GET_REPLICATION,
- GNUNET_DHT_RO_NONE,
+ route_option,
NULL, 0,
NULL, 0,
&get_result_iterator,
GNUNET_DHT_put(test_put->dht_handle,
&key,
DEFAULT_PUT_REPLICATION,
- GNUNET_DHT_RO_NONE,
+ route_option,
GNUNET_BLOCK_TYPE_TEST,
sizeof(data), data,
GNUNET_TIME_UNIT_FOREVER_ABS,
char * connect_topology_option_str;
char * connect_topology_option_modifier_string;
+#if PATH_TRACKING
+ route_option = GNUNET_DHT_RO_RECORD_ROUTE;
+#else
+ route_option = GNUNET_DHT_RO_NONE;
+#endif
+
/* Get path from configuration file */
if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string(cfg, "paths", "servicehome", &test_directory))
{
[fs]
AUTOSTART = NO
+[resolver]
+AUTOSTART = NO
+
[dht]
DEBUG = NO
-STOP_ON_CLOSEST = NO
+STOP_ON_CLOSEST = YES
AUTOSTART = YES
ACCEPT_FROM6 = ::1;
ACCEPT_FROM = 127.0.0.1;
-BINARY = gnunet-service-dht
+#BINARY = /home/mrwiggles/documents/research/gnunet/gnunet-ng/src/dht/.libs/gnunet-service-dht
#PREFIX = xterm -T dht -e gdb --args
#PREFIX = valgrind --log-file=dht_%p
CONFIG = $DEFAULTCONFIG
HOME = $SERVICEHOME
HOSTNAME = localhost
PORT = 2100
+STOP_FOUND = YES
+USE_MAX_HOPS = YES
+MAX_HOPS = 16
+CONVERGE_BINARY = YES
+CONVERGE_MODIFIER = 4
[block]
plugins = test dht
PORT = 12368
[DHT_TESTING]
-MYSQL_LOGGING_EXTENDED = YES
-NUM_GETS = 10
-NUM_PUTS = 50
+MYSQL_LOGGING_EXTENDED = NO
+MYSQL_LOGGING = NO
+NUM_GETS = 1
+NUM_PUTS = 1
[TESTING]
TOPOLOGY = CLIQUE
#LOGNMODIFIER = .65
#PERCENTAGE = .75
WEAKRANDOM = YES
-NUM_PEERS = 15
+NUM_PEERS = 5
[gnunetd]
HOSTKEY = $SERVICEHOME/.hostkey
&stop_retry_get, get_context);
get_context->get_handle = GNUNET_DHT_get_start(get_context->dht_handle,
GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5),
- 0 /* FIXME: use real type */, &get_context->peer->hashPubKey,
+ GNUNET_BLOCK_TYPE_DHT_HELLO,
+ &get_context->peer->hashPubKey,
DEFAULT_GET_REPLICATION,
GNUNET_DHT_RO_NONE,
NULL, 0,
curr_get_ctx.dht_handle = peer1dht;
curr_get_ctx.peer = &peer2id;
- //GNUNET_SCHEDULER_add_now (&do_get, &curr_get_ctx);
GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 2), &do_get, &curr_get_ctx);
}
else if (total_connections + failed_connections == expected_connections)
[fs]
AUTOSTART = NO
+[resolver]
+AUTOSTART = YES
+
[dht]
DEBUG = NO
AUTOSTART = YES
--- /dev/null
+/*
+ This file is part of GNUnet.
+ (C) 2009 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 3, 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 dht/test_dht_twopeer_path_tracking.c
+ * @brief testcase for testing DHT service with
+ * two running peers, logging the path of the dht requests.
+ */
+#include "platform.h"
+#include "gnunet_testing_lib.h"
+#include "gnunet_core_service.h"
+#include "gnunet_dht_service.h"
+
+/* DEFINES */
+#define VERBOSE GNUNET_NO
+
+/* Timeout for entire testcase */
+#define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
+
+/* Timeout for waiting for replies to get requests */
+#define GET_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30)
+
+/* If number of peers not in config file, use this number */
+#define DEFAULT_NUM_PEERS 2
+
+/* Globals */
+
+/**
+ * Directory to store temp data in, defined in config file
+ */
+static char *test_directory;
+
+/**
+ * Variable used to store the number of connections we should wait for.
+ */
+static unsigned int expected_connections;
+
+/**
+ * Variable used to keep track of how many peers aren't yet started.
+ */
+static unsigned long long peers_left;
+
+/**
+ * Handle to the set of all peers run for this test.
+ */
+static struct GNUNET_TESTING_PeerGroup *pg;
+
+/**
+ * Global handle we will use for GET requests.
+ */
+struct GNUNET_DHT_GetHandle *global_get_handle;
+
+
+/**
+ * Total number of peers to run, set based on config file.
+ */
+static unsigned long long num_peers;
+
+/**
+ * Global used to count how many connections we have currently
+ * been notified about (how many times has topology_callback been called
+ * with success?)
+ */
+static unsigned int total_connections;
+
+/**
+ * Global used to count how many failed connections we have
+ * been notified about (how many times has topology_callback
+ * been called with failure?)
+ */
+static unsigned int failed_connections;
+
+/* Task handle to use to schedule test failure */
+GNUNET_SCHEDULER_TaskIdentifier die_task;
+
+/* Global return value (0 for success, anything else for failure) */
+static int ok;
+
+/**
+ * Peer identity of the first peer started.
+ */
+static struct GNUNET_PeerIdentity peer1id;
+
+/**
+ * Peer identity of the second peer started.
+ */
+static struct GNUNET_PeerIdentity peer2id;
+
+/**
+ * Handle to the first peers DHT service (via the API)
+ */
+static struct GNUNET_DHT_Handle *peer1dht;
+
+/**
+ * Handle to the second peers DHT service (via the API)
+ */
+static struct GNUNET_DHT_Handle *peer2dht;
+
+/**
+ * Check whether peers successfully shut down.
+ */
+void shutdown_callback (void *cls,
+ const char *emsg)
+{
+ if (emsg != NULL)
+ {
+ if (ok == 0)
+ ok = 2;
+ }
+}
+
+/**
+ * Function scheduled to be run on the successful completion of this
+ * testcase. Specifically, called when our get request completes.
+ */
+static void
+finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
+{
+ GNUNET_assert (pg != NULL);
+ GNUNET_assert (peer1dht != NULL);
+ GNUNET_assert (peer2dht != NULL);
+ GNUNET_DHT_disconnect(peer1dht);
+ GNUNET_DHT_disconnect(peer2dht);
+ GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
+ ok = 0;
+}
+
+/**
+ * Continuation for the GNUNET_DHT_get_stop call, so that we don't shut
+ * down the peers without freeing memory associated with GET request.
+ */
+static void
+end_badly_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
+{
+ if (peer1dht != NULL)
+ GNUNET_DHT_disconnect(peer1dht);
+
+ if (peer2dht != NULL)
+ GNUNET_DHT_disconnect(peer2dht);
+
+ if (pg != NULL)
+ GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
+}
+
+/**
+ * Check if the get_handle is being used, if so stop the request. Either
+ * way, schedule the end_badly_cont function which actually shuts down the
+ * test.
+ */
+static void
+end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failing test with error: `%s'!\n", (char *)cls);
+ if (global_get_handle != NULL)
+ {
+ GNUNET_DHT_get_stop(global_get_handle);
+ global_get_handle = NULL;
+ }
+ GNUNET_SCHEDULER_add_now(&end_badly_cont, NULL);
+ ok = 1;
+}
+
+/**
+ * Iterator called if the GET request initiated returns a response.
+ *
+ * @param cls closure
+ * @param exp when will this value expire
+ * @param key key of the result
+ * @param type type of the result
+ * @param size number of bytes in data
+ * @param data pointer to the result data
+ */
+void get_result_iterator (void *cls,
+ struct GNUNET_TIME_Absolute exp,
+ const GNUNET_HashCode * key,
+ const struct GNUNET_PeerIdentity * const *get_path,
+ const struct GNUNET_PeerIdentity * const *put_path,
+ enum GNUNET_BLOCK_Type type,
+ size_t size,
+ const void *data)
+{
+ GNUNET_HashCode original_key; /* Key data was stored data under */
+ char original_data[4]; /* Made up data that was stored */
+ memset(&original_key, 42, sizeof(GNUNET_HashCode)); /* Set the key to what it was set to previously */
+ memset(original_data, 43, sizeof(original_data));
+#if VERBOSE
+ unsigned int i;
+#endif
+
+ if ((0 != memcmp(&original_key, key, sizeof (GNUNET_HashCode))) || (0 != memcmp(original_data, data, sizeof(original_data))))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Key or data is not the same as was inserted!\n");
+ GNUNET_SCHEDULER_cancel(die_task);
+ GNUNET_SCHEDULER_add_now(&end_badly, "key or data mismatch in get response!\n");
+ return;
+ }
+
+#if VERBOSE
+ if (put_path != NULL)
+ {
+ fprintf(stderr, "PUT Path: ");
+ for (i = 0; put_path[i] != NULL; i++)
+ fprintf(stderr, "%s%s", i == 0 ? "" : "->", GNUNET_i2s(put_path[i]));
+ fprintf(stderr, "\n");
+ }
+ if (get_path != NULL)
+ {
+ fprintf(stderr, "GET Path: ");
+ for (i = 0; get_path[i] != NULL; i++)
+ fprintf(stderr, "%s%s", i == 0 ? "" : "->", GNUNET_i2s(get_path[i]));
+ fprintf(stderr, "\n");
+ }
+#endif
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received correct GET response!\n");
+ GNUNET_SCHEDULER_cancel(die_task);
+ GNUNET_DHT_get_stop(global_get_handle);
+ GNUNET_SCHEDULER_add_now (&finish_testing, NULL);
+}
+
+/**
+ * Start the GET request for the same key/data that was inserted.
+ */
+static void
+do_get (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
+{
+ GNUNET_HashCode key; /* Key for data lookup */
+ memset(&key, 42, sizeof(GNUNET_HashCode)); /* Set the key to the same thing as when data was inserted */
+ global_get_handle = GNUNET_DHT_get_start(peer2dht, GNUNET_TIME_relative_get_forever(),
+ GNUNET_BLOCK_TYPE_TEST,
+ &key,
+ DEFAULT_GET_REPLICATION,
+ GNUNET_DHT_RO_RECORD_ROUTE,
+ NULL, 0,
+ NULL, 0,
+ &get_result_iterator, NULL);
+}
+
+/**
+ * Called when the PUT request has been transmitted to the DHT service.
+ * Schedule the GET request for some time in the future.
+ */
+static void
+put_finished (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
+{
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_delayed (GET_TIMEOUT,
+ &end_badly, "waiting for get response (data not found)");
+ GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 10), &do_get, NULL);
+}
+
+/**
+ * Set up some data, and call API PUT function
+ */
+static void
+do_put (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
+{
+ GNUNET_HashCode key; /* Made up key to store data under */
+ char data[4]; /* Made up data to store */
+ memset(&key, 42, sizeof(GNUNET_HashCode)); /* Set the key to something simple so we can issue GET request */
+ memset(data, 43, sizeof(data));
+
+ /* Insert the data at the first peer */
+ GNUNET_DHT_put(peer1dht,
+ &key,
+ DEFAULT_PUT_REPLICATION,
+ GNUNET_DHT_RO_RECORD_ROUTE,
+ GNUNET_BLOCK_TYPE_TEST,
+ sizeof(data), data,
+ GNUNET_TIME_UNIT_FOREVER_ABS,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &put_finished, NULL);
+}
+
+/**
+ * This function is called whenever a connection attempt is finished between two of
+ * the started peers (started with GNUNET_TESTING_daemons_start). The total
+ * number of times this function is called should equal the number returned
+ * from the GNUNET_TESTING_connect_topology call.
+ *
+ * The emsg variable is NULL on success (peers connected), and non-NULL on
+ * failure (peers failed to connect).
+ */
+void
+topology_callback (void *cls,
+ const struct GNUNET_PeerIdentity *first,
+ const struct GNUNET_PeerIdentity *second,
+ uint32_t distance,
+ const struct GNUNET_CONFIGURATION_Handle *first_cfg,
+ const struct GNUNET_CONFIGURATION_Handle *second_cfg,
+ struct GNUNET_TESTING_Daemon *first_daemon,
+ struct GNUNET_TESTING_Daemon *second_daemon,
+ const char *emsg)
+{
+ if (emsg == NULL)
+ {
+ total_connections++;
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s, distance %u\n",
+ first_daemon->shortname,
+ second_daemon->shortname,
+ distance);
+#endif
+ }
+#if VERBOSE
+ else
+ {
+ failed_connections++;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect peer %s to peer %s with error :\n%s\n",
+ first_daemon->shortname,
+ second_daemon->shortname, emsg);
+ }
+#endif
+
+ if (total_connections == expected_connections)
+ {
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Created %d total connections, which is our target number! Starting next phase of testing.\n",
+ total_connections);
+#endif
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
+ &end_badly, "from test gets");
+
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 2), &do_put, NULL);
+ }
+ else if (total_connections + failed_connections == expected_connections)
+ {
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, "from topology_callback (too many failed connections)");
+ }
+}
+
+
+/**
+ * Callback which is called whenever a peer is started (as a result of the
+ * GNUNET_TESTING_daemons_start call.
+ *
+ * @param cls closure argument given to GNUNET_TESTING_daemons_start
+ * @param id the GNUNET_PeerIdentity of the started peer
+ * @param cfg the configuration for this specific peer (needed to connect
+ * to the DHT)
+ * @param d the handle to the daemon started
+ * @param emsg NULL if peer started, non-NULL on error
+ */
+static void
+peers_started_callback (void *cls,
+ const struct GNUNET_PeerIdentity *id,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ struct GNUNET_TESTING_Daemon *d, const char *emsg)
+{
+ if (emsg != NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to start daemon with error: `%s'\n",
+ emsg);
+ return;
+ }
+ GNUNET_assert (id != NULL);
+
+ /* This is the first peer started */
+ if (peers_left == num_peers)
+ {
+ memcpy(&peer1id, id, sizeof(struct GNUNET_PeerIdentity)); /* Save the peer id */
+ peer1dht = GNUNET_DHT_connect(cfg, 100); /* Connect to the first peers DHT service */
+ if (peer1dht == NULL) /* If DHT connect failed */
+ {
+ GNUNET_SCHEDULER_cancel (die_task);
+ GNUNET_SCHEDULER_add_now(&end_badly, "Failed to get dht handle!\n");
+ }
+ }
+ else /* This is the second peer started */
+ {
+ memcpy(&peer2id, id, sizeof(struct GNUNET_PeerIdentity)); /* Same as for first peer... */
+ peer2dht = GNUNET_DHT_connect(cfg, 100);
+ if (peer2dht == NULL)
+ {
+ GNUNET_SCHEDULER_cancel (die_task);
+ GNUNET_SCHEDULER_add_now(&end_badly, "Failed to get dht handle!\n");
+ }
+ }
+
+ /* Decrement number of peers left to start */
+ peers_left--;
+
+ if (peers_left == 0) /* Indicates all peers started */
+ {
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "All %d daemons started, now connecting peers!\n",
+ num_peers);
+#endif
+ expected_connections = -1;
+ if ((pg != NULL)) /* Sanity check */
+ {
+ /* Connect peers in a "straight line" topology, return the number of expected connections */
+ expected_connections = GNUNET_TESTING_connect_topology (pg, GNUNET_TESTING_TOPOLOGY_LINE, GNUNET_TESTING_TOPOLOGY_OPTION_ALL, 0.0, NULL, NULL);
+ }
+
+ /* Cancel current timeout fail task */
+ GNUNET_SCHEDULER_cancel (die_task);
+ if (expected_connections == GNUNET_SYSERR) /* Some error happened */
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, "from connect topology (bad return)");
+
+ /* Schedule timeout on failure task */
+ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
+ &end_badly, "from connect topology (timeout)");
+ ok = 0;
+ }
+}
+
+static void
+run (void *cls,
+ char *const *args,
+ const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+
+ /* Get path from configuration file */
+ if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string(cfg, "paths", "servicehome", &test_directory))
+ {
+ ok = 404;
+ return;
+ }
+
+ /* Get number of peers to start from configuration (should be two) */
+ if (GNUNET_SYSERR ==
+ GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers",
+ &num_peers))
+ num_peers = DEFAULT_NUM_PEERS;
+
+ /* Set peers_left so we know when all peers started */
+ peers_left = num_peers;
+
+ /* Set up a task to end testing if peer start fails */
+ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
+ &end_badly, "didn't start all daemons in reasonable amount of time!!!");
+
+ /* Start num_peers peers, call peers_started_callback on peer start, topology_callback on peer connect */
+ /* Read the API documentation for other parameters! */
+ pg = GNUNET_TESTING_daemons_start (cfg,
+ num_peers, TIMEOUT, NULL, NULL, &peers_started_callback, NULL,
+ &topology_callback, NULL, NULL);
+
+}
+
+static int
+check ()
+{
+ int ret;
+ /* Arguments for GNUNET_PROGRAM_run */
+ char *const argv[] = {"test-dht-twopeer-put-get", /* Name to give running binary */
+ "-c",
+ "test_dht_twopeer_data.conf", /* Config file to use */
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ NULL
+ };
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+ /* Run the run function as a new program */
+ ret = GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
+ argv, "test-dht-twopeer-put-get", "nohelp",
+ options, &run, &ok);
+ if (ret != GNUNET_OK)
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "`test-dht-twopeer': Failed with error code %d\n", ret);
+ }
+ return ok;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int ret;
+
+ GNUNET_log_setup ("test-dht-twopeer",
+#if VERBOSE
+ "DEBUG",
+#else
+ "WARNING",
+#endif
+ NULL);
+ ret = check ();
+ /**
+ * Need to remove base directory, subdirectories taken care
+ * of by the testing framework.
+ */
+ if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK)
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Failed to remove testing directory %s\n", test_directory);
+ }
+ return ret;
+}
+
+/* end of test_dht_twopeer_put_get.c */
#include "gnunet_protocols.h"
#include "dhtlog.h"
-#define VERBOSE GNUNET_YES
+#define VERBOSE GNUNET_NO
static int ok;
SERVICEHOME = /tmp/test-dhtlog/
[DHTLOG]
-#PLUGIN = mysql_dump
+#PLUGIN = mysql_dump_load
PLUGIN = dummy
#PLUGIN = mysql