From: Nathan S. Evans Date: Wed, 2 Feb 2011 11:54:21 +0000 (+0000) Subject: path tracking commit, hopefully a fix for dht_api connect bug, needs tested X-Git-Tag: initial-import-from-subversion-38251~19217 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=0aa66524bd2ef85668ba8de14792eb39480b59ba;p=oweals%2Fgnunet.git path tracking commit, hopefully a fix for dht_api connect bug, needs tested --- diff --git a/src/dht/Makefile.am b/src/dht/Makefile.am index d361f536a..ddcfccd46 100644 --- a/src/dht/Makefile.am +++ b/src/dht/Makefile.am @@ -52,7 +52,7 @@ libgnunet_plugin_dhtlog_mysql_dump_la_LIBADD = \ $(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 = \ @@ -69,6 +69,7 @@ libgnunetdhtlog_la_LDFLAGS = \ $(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 \ @@ -84,12 +85,10 @@ bin_PROGRAMS = $(STUD_PROGS) \ 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 @@ -151,14 +150,17 @@ check_PROGRAMS = $(STUD_TESTS) \ 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 = \ @@ -179,13 +181,6 @@ test_dht_multipeer_LDADD = \ 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 = \ @@ -201,6 +196,13 @@ test_dht_twopeer_put_get_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 diff --git a/src/dht/dht.h b/src/dht/dht.h index 4e8782bb5..1ea888093 100644 --- a/src/dht/dht.h +++ b/src/dht/dht.h @@ -199,18 +199,11 @@ struct GNUNET_DHT_RouteResultMessage 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 @@ -223,11 +216,9 @@ struct GNUNET_DHT_RouteResultMessage */ GNUNET_HashCode key; - /* PUT path */ - - /* GET path */ - /* GNUNET_MessageHeader *enc actual DHT message, copied to end of this dealy do */ + + /* OUTGOING path */ }; @@ -267,11 +258,11 @@ struct GNUNET_DHT_P2PRouteMessage 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 @@ -290,6 +281,8 @@ struct GNUNET_DHT_P2PRouteMessage /* GNUNET_MessageHeader *enc actual DHT message, copied to end of this dealy do */ + /* OUTGOING PATH */ + }; /** @@ -307,7 +300,7 @@ struct GNUNET_DHT_P2PRouteResultMessage * (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 @@ -341,12 +334,9 @@ struct GNUNET_DHT_P2PRouteResultMessage 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 */ }; @@ -449,7 +439,13 @@ struct GNUNET_DHT_GetResultMessage /** * 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? @@ -458,5 +454,27 @@ struct GNUNET_DHT_GetResultMessage }; +/** + * 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_ */ diff --git a/src/dht/dht_api.c b/src/dht/dht_api.c index 285ec1a30..c65699d7a 100644 --- a/src/dht/dht_api.c +++ b/src/dht/dht_api.c @@ -181,6 +181,17 @@ struct GNUNET_DHT_Handle */ 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. */ @@ -266,31 +277,62 @@ add_request_to_pending (void *cls, /** - * 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); } @@ -302,8 +344,11 @@ process_pending_messages (struct GNUNET_DHT_Handle *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)) @@ -316,7 +361,7 @@ process_pending_messages (struct GNUNET_DHT_Handle *handle) handle); if (NULL == handle->th) { - reconnect (handle); + do_disconnect (handle); return; } } @@ -337,7 +382,7 @@ transmit_pending (void *cls, handle->th = NULL; if (buf == NULL) { - reconnect (handle); + do_disconnect (handle); return 0; } if (NULL == (head = handle->pending_head)) @@ -377,8 +422,6 @@ transmit_pending (void *cls, } - - /** * Process a given reply that might match the given * request. @@ -393,12 +436,11 @@ process_reply (void *cls, 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) @@ -407,62 +449,43 @@ process_reply (void *cls, "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 0) + + if (outgoing_path_length > 0) { - get_path = GNUNET_malloc ((gpl+1) * sizeof (struct GNUNET_PeerIdentity*)); - for (i=0;isize)) - { - 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; } @@ -485,19 +508,19 @@ service_message_handler (void *cls, { 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; diff --git a/src/dht/dht_api_find_peer.c b/src/dht/dht_api_find_peer.c index cd3bed5ba..8196e394c 100644 --- a/src/dht/dht_api_find_peer.c +++ b/src/dht/dht_api_find_peer.c @@ -65,17 +65,15 @@ struct GNUNET_DHT_FindPeerHandle * * @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; diff --git a/src/dht/dht_api_get_put.c b/src/dht/dht_api_get_put.c index 3b7a6d83a..5b5baa531 100644 --- a/src/dht/dht_api_get_put.c +++ b/src/dht/dht_api_get_put.c @@ -124,22 +124,25 @@ struct GNUNET_DHT_GetHandle * * @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) { @@ -150,15 +153,36 @@ get_reply_iterator (void *cls, 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); } diff --git a/src/dht/gnunet-service-dht.c b/src/dht/gnunet-service-dht.c index b8f7e4732..2f5be7691 100644 --- a/src/dht/gnunet-service-dht.c +++ b/src/dht/gnunet-service-dht.c @@ -1096,6 +1096,10 @@ forward_result_message (const struct GNUNET_MessageHeader *msg, 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 = @@ -1118,6 +1122,13 @@ forward_result_message (const struct GNUNET_MessageHeader *msg, /* 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); @@ -1128,7 +1139,13 @@ forward_result_message (const struct GNUNET_MessageHeader *msg, 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", @@ -1774,7 +1791,7 @@ forward_message (const struct GNUNET_MessageHeader *msg, 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 */ @@ -1992,18 +2009,23 @@ add_pending_message (struct ClientList *client, 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); @@ -2014,11 +2036,24 @@ send_reply_to_client (struct ClientList *client, 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); } @@ -2105,6 +2140,8 @@ route_result_message (struct GNUNET_MessageHeader *msg, struct DHTRouteSource *pos; struct PeerInfo *peer_info; const struct GNUNET_MessageHeader *hello_msg; + unsigned int i; + char *path_offset; increment_stats (STAT_RESULTS); /** @@ -2221,8 +2258,12 @@ route_result_message (struct GNUNET_MessageHeader *msg, 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 */ { @@ -2313,6 +2354,12 @@ datacache_get_iterator (void *cls, 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, @@ -2326,6 +2373,24 @@ datacache_get_iterator (void *cls, 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: @@ -2339,15 +2404,32 @@ datacache_get_iterator (void *cls, 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); @@ -2367,7 +2449,7 @@ datacache_get_iterator (void *cls, 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; @@ -2385,7 +2467,7 @@ datacache_get_iterator (void *cls, 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 @@ -2781,6 +2863,9 @@ handle_dht_put (const struct GNUNET_MessageHeader *msg, 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; @@ -2789,7 +2874,6 @@ handle_dht_put (const struct GNUNET_MessageHeader *msg, 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 @@ -2897,8 +2981,22 @@ handle_dht_put (const struct GNUNET_MessageHeader *msg, 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)); @@ -4776,7 +4874,7 @@ handle_dht_p2p_route_request (void *cls, 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) + @@ -4786,7 +4884,7 @@ handle_dht_p2p_route_request (void *cls, 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; @@ -4829,7 +4927,10 @@ handle_dht_p2p_route_result (void *cls, 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); @@ -4871,16 +4972,22 @@ handle_dht_p2p_route_result (void *cls, 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; @@ -5057,7 +5164,7 @@ handle_core_connect (void *cls, 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; @@ -5079,10 +5186,18 @@ handle_core_connect (void *cls, } 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) { diff --git a/src/dht/test_dht_api_data.conf b/src/dht/test_dht_api_data.conf index 24e3bca30..0fd416704 100644 --- a/src/dht/test_dht_api_data.conf +++ b/src/dht/test_dht_api_data.conf @@ -5,6 +5,9 @@ DEFAULTCONFIG = test_dht_api_data.conf [fs] AUTOSTART = NO +[resolver] +AUTOSTART = NO + [datastore-sqlite] FILENAME = $SERVICEHOME/datastore/sqlite.db diff --git a/src/dht/test_dht_api_peer1.conf b/src/dht/test_dht_api_peer1.conf index 597e7af8f..12457a16a 100644 --- a/src/dht/test_dht_api_peer1.conf +++ b/src/dht/test_dht_api_peer1.conf @@ -1,6 +1,9 @@ [fs] AUTOSTART = NO +[resolver] +AUTOSTART = NO + [dht] DEBUG = NO AUTOSTART = YES diff --git a/src/dht/test_dht_multipeer.c b/src/dht/test_dht_multipeer.c index 24618230a..e4d1a7d20 100644 --- a/src/dht/test_dht_multipeer.c +++ b/src/dht/test_dht_multipeer.c @@ -53,6 +53,8 @@ #define MAX_OUTSTANDING_GETS 10 +#define PATH_TRACKING GNUNET_YES + /* Structs */ struct TestPutContext @@ -206,6 +208,8 @@ static unsigned int total_connections; */ static unsigned int failed_connections; +enum GNUNET_DHT_RouteOption route_option; + /* Task handle to use to schedule test failure */ GNUNET_SCHEDULER_TaskIdentifier die_task; @@ -224,7 +228,6 @@ static double connect_topology_option_modifier = 0.0; /* Global return value (0 for success, anything else for failure) */ static int ok; - /** * Check whether peers successfully shut down. */ @@ -395,13 +398,30 @@ void get_result_iterator (void *cls, 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"); @@ -448,7 +468,7 @@ do_get (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc) GNUNET_BLOCK_TYPE_TEST, &key, DEFAULT_GET_REPLICATION, - GNUNET_DHT_RO_NONE, + route_option, NULL, 0, NULL, 0, &get_result_iterator, @@ -517,7 +537,7 @@ do_put (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc) 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, @@ -758,6 +778,12 @@ run (void *cls, 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)) { diff --git a/src/dht/test_dht_multipeer_data.conf b/src/dht/test_dht_multipeer_data.conf index 17ebedbbd..c96560ccc 100644 --- a/src/dht/test_dht_multipeer_data.conf +++ b/src/dht/test_dht_multipeer_data.conf @@ -1,19 +1,27 @@ [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 @@ -65,9 +73,10 @@ TIMEOUT = 300000 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 @@ -77,7 +86,7 @@ CONNECT_TOPOLOGY = RING #LOGNMODIFIER = .65 #PERCENTAGE = .75 WEAKRANDOM = YES -NUM_PEERS = 15 +NUM_PEERS = 5 [gnunetd] HOSTKEY = $SERVICEHOME/.hostkey diff --git a/src/dht/test_dht_twopeer.c b/src/dht/test_dht_twopeer.c index d5923dc11..aab3a1231 100644 --- a/src/dht/test_dht_twopeer.c +++ b/src/dht/test_dht_twopeer.c @@ -220,7 +220,8 @@ get_stop_finished (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc) &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, @@ -303,7 +304,6 @@ topology_callback (void *cls, 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) diff --git a/src/dht/test_dht_twopeer_data.conf b/src/dht/test_dht_twopeer_data.conf index 5110b3001..5df598d00 100644 --- a/src/dht/test_dht_twopeer_data.conf +++ b/src/dht/test_dht_twopeer_data.conf @@ -1,6 +1,9 @@ [fs] AUTOSTART = NO +[resolver] +AUTOSTART = YES + [dht] DEBUG = NO AUTOSTART = YES diff --git a/src/dht/test_dht_twopeer_path_tracking.c b/src/dht/test_dht_twopeer_path_tracking.c new file mode 100644 index 000000000..ab4bc81e0 --- /dev/null +++ b/src/dht/test_dht_twopeer_path_tracking.c @@ -0,0 +1,513 @@ +/* + 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 */ diff --git a/src/dht/test_dhtlog.c b/src/dht/test_dhtlog.c index c8601b191..955781ef2 100644 --- a/src/dht/test_dhtlog.c +++ b/src/dht/test_dhtlog.c @@ -28,7 +28,7 @@ #include "gnunet_protocols.h" #include "dhtlog.h" -#define VERBOSE GNUNET_YES +#define VERBOSE GNUNET_NO static int ok; diff --git a/src/dht/test_dhtlog_data.conf b/src/dht/test_dhtlog_data.conf index 22ef427aa..26244af0d 100644 --- a/src/dht/test_dhtlog_data.conf +++ b/src/dht/test_dhtlog_data.conf @@ -36,7 +36,7 @@ DEFAULTCONFIG = test_dhtlog_data.conf SERVICEHOME = /tmp/test-dhtlog/ [DHTLOG] -#PLUGIN = mysql_dump +#PLUGIN = mysql_dump_load PLUGIN = dummy #PLUGIN = mysql