+ layer = ntohs (m->layer);
+ if (layer > NUMBER_LAYERED_ID)
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ t = GNUNET_new (struct Trail);
+ t->pred_id = m->trail_id;
+ t->pred = pred;
+ if (GNUNET_OK !=
+ GNUNET_CONTAINER_multihashmap_put (trail_map,
+ &t->pred_id,
+ t,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (t);
+ return;
+ }
+ GNUNET_CONTAINER_MDLL_insert (pred,
+ pred->pred_head,
+ pred->pred_tail,
+ t);
+ t->expiration_time = GNUNET_TIME_relative_to_absolute (TRAIL_TIMEOUT);
+ t->hn = GNUNET_CONTAINER_heap_insert (trail_heap,
+ t,
+ t->expiration_time.abs_value_us);
+ if (NULL == trail_timeout_task)
+ trail_timeout_task = GNUNET_SCHEDULER_add_delayed (TRAIL_TIMEOUT,
+ &trail_timeout_callback,
+ NULL);
+
+ if (ntohl (m->hops_taken) > GDS_NSE_get ())
+ {
+ /* We are the last hop, generate response */
+ struct GNUNET_MQ_Envelope *env;
+ struct RandomWalkResponseMessage *rwrm;
+
+ env = GNUNET_MQ_msg (rwrm,
+ GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK_RESPONSE);
+ rwrm->reserved = htonl (0);
+ rwrm->trail_id = m->trail_id;
+ if (0 == layer)
+ (void) GDS_DATACACHE_get_random_key (&rwrm->location);
+ else
+ {
+ struct FingerTable *ft;
+
+ ft = &fingers[layer-1];
+ if (0 == ft->number_valid_fingers)
+ {
+ GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE,
+ &rwrm->location);
+ }
+ else
+ {
+ struct Finger *f;
+ unsigned int off;
+ unsigned int i;
+
+ off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
+ ft->number_valid_fingers);
+ for (i=0; (NULL == (f = ft->fingers[i])) || (off > 0); i++)
+ if (NULL != f) off--;
+ rwrm->location = f->destination;
+ }
+ }
+ GNUNET_MQ_send (pred->mq,
+ env);
+ }
+ else
+ {
+ struct GNUNET_MQ_Envelope *env;
+ struct RandomWalkMessage *rwm;
+ struct FriendInfo *succ;
+
+ /* extend the trail by another random hop */
+ succ = pick_random_friend ();
+ GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE,
+ &t->succ_id);
+ t->succ = succ;
+ if (GNUNET_OK !=
+ GNUNET_CONTAINER_multihashmap_put (trail_map,
+ &t->succ_id,
+ t,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
+ {
+ GNUNET_break (0);
+ GNUNET_CONTAINER_MDLL_remove (pred,
+ pred->pred_head,
+ pred->pred_tail,
+ t);
+ GNUNET_free (t);
+ return;
+ }
+ GNUNET_CONTAINER_MDLL_insert (succ,
+ succ->succ_head,
+ succ->succ_tail,
+ t);
+ env = GNUNET_MQ_msg (rwm,
+ GNUNET_MESSAGE_TYPE_WDHT_RANDOM_WALK);
+ rwm->hops_taken = htons (1 + ntohs (m->hops_taken));
+ rwm->layer = m->layer;
+ rwm->trail_id = t->succ_id;
+ GNUNET_MQ_send (succ->mq,
+ env);
+ }