2 This file is part of GNUnet.
3 Copyright (C) 2009-2013 GNUnet e.V.
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
21 * @file gns/gnunet-service-gns_reverser.c
22 * @brief GNUnet GNS service
23 * @author Martin Schanzenbach
28 #include "gnunet_gns_service.h"
29 #include "gnunet-service-gns_resolver.h"
30 #include "gnunet-service-gns_reverser.h"
32 struct ReverseRecordEntry
37 struct ReverseRecordEntry *next;
42 struct ReverseRecordEntry *prev;
47 struct GNUNET_GNSRECORD_ReverseRecord *record;
61 struct ReverseRecordEntry *records_head;
66 struct ReverseRecordEntry *records_tail;
71 uint64_t record_count;
74 * Current delegation to expect
76 struct GNUNET_CRYPTO_EcdsaPublicKey target;
81 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
85 struct ReverseTreeNode
90 struct ReverseTreeNode *next;
95 struct ReverseTreeNode *prev;
98 * Resolved name until now
103 * Depth of the resolution at this node
108 * The pkey of the namespace
110 struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
115 struct GNS_ReverserHandle
118 * GNS resolver handle
120 struct GNS_ResolverHandle *rh;
123 * The authority to look for
125 struct GNUNET_CRYPTO_EcdsaPublicKey authority;
128 * Resolution candidate queue
130 struct ReverseTreeNode *node_queue_head;
133 * Resolution candidate queue
135 struct ReverseTreeNode *node_queue_tail;
138 * Max depth for the resolution
145 GNS_ReverseResultProcessor proc;
154 * Reverse record collection task
156 static struct GNUNET_SCHEDULER_Task *reverse_record_check_task;
161 static struct GNUNET_SCHEDULER_Task *it_task;
166 static struct GNS_ResolverHandle *gns_lookup_reverse;
171 static struct GNUNET_NAMESTORE_Handle *ns;
176 static struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter;
179 * The zone target for reverse record resolution
181 static struct GNUNET_CRYPTO_EcdsaPublicKey myzone;
184 * The zone target for reverse record resolution
186 static struct GNUNET_CRYPTO_EcdsaPrivateKey pzone;
189 * The nick of our zone
195 cleanup_handle (struct GNS_ReverserHandle *rh)
197 struct ReverseTreeNode *rtn;
199 for (rtn = rh->node_queue_head; NULL != rtn; rtn = rh->node_queue_head)
201 if (NULL != rtn->name)
202 GNUNET_free (rtn->name);
203 GNUNET_CONTAINER_DLL_remove (rh->node_queue_head,
212 handle_gns_result (void *cls,
214 const struct GNUNET_GNSRECORD_Data *rd)
216 struct GNS_ReverserHandle *rh = cls;
217 const struct GNUNET_GNSRECORD_ReverseRecord *rr;
218 struct ReverseTreeNode *rtn;
221 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
222 "Got result (%d)\n", rd_count);
224 for (int i = 0; i < rd_count; i++)
227 * Check if we are in the delegation set
229 if (GNUNET_GNSRECORD_TYPE_REVERSE != rd[i].record_type)
232 name = (const char*) &rr[1];
233 if (0 == memcmp (&rh->authority,
235 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
238 GNUNET_asprintf (&result,
240 rh->node_queue_head->name,
242 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
243 "Found path from %s\n", result);
245 rh->proc (rh->proc_cls, result);
247 GNUNET_free (result);
250 if (rh->node_queue_head->depth >= rh->max_depth)
252 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
253 "Found REVERSE from %s\n", name);
255 rtn = GNUNET_new (struct ReverseTreeNode);
256 if (NULL == rh->node_queue_head->name)
257 rtn->name = GNUNET_strdup (name);
259 GNUNET_asprintf (&rtn->name,
261 rh->node_queue_head->name,
263 rtn->depth = rh->node_queue_head->depth + 1;
264 rtn->pkey = rr->pkey;
265 GNUNET_CONTAINER_DLL_insert_tail (rh->node_queue_head,
272 * Done here remove node from queue
274 rtn = rh->node_queue_head;
276 GNUNET_CONTAINER_DLL_remove (rh->node_queue_head,
279 if (NULL == rh->node_queue_head)
282 rh->proc (rh->proc_cls, NULL);
286 rh->rh = GNS_resolver_lookup (&rh->node_queue_head->pkey,
287 GNUNET_GNSRECORD_TYPE_REVERSE,
290 GNUNET_GNS_LO_DEFAULT,
296 * Reverse lookup of a specific zone
297 * calls RecordLookupProcessor on result or timeout
299 * @param target the zone to perform the lookup in
300 * @param authority the authority
301 * @param proc the processor to call
302 * @param proc_cls the closure to pass to @a proc
303 * @return handle to cancel operation
305 struct GNS_ReverserHandle *
306 GNS_reverse_lookup (const struct GNUNET_CRYPTO_EcdsaPublicKey *target,
307 const struct GNUNET_CRYPTO_EcdsaPublicKey *authority,
308 GNS_ReverseResultProcessor proc,
311 struct GNS_ReverserHandle *rh;
312 struct ReverseTreeNode *rtn;
314 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
315 "Starting reverse resolution\n");
316 rh = GNUNET_new (struct GNS_ReverserHandle);
318 rh->proc_cls = proc_cls;
319 rtn = GNUNET_new (struct ReverseTreeNode);
323 GNUNET_CONTAINER_DLL_insert (rh->node_queue_head,
326 rh->authority = *authority;
327 rh->max_depth = 3; //TODO make argument
328 rh->rh = GNS_resolver_lookup (target,
329 GNUNET_GNSRECORD_TYPE_REVERSE,
332 GNUNET_GNS_LO_DEFAULT,
339 * Cancel active resolution (i.e. client disconnected).
341 * @param rh resolution to abort
344 GNS_reverse_lookup_cancel (struct GNS_ReverserHandle *rh)
350 /********************************************
352 * ******************************************/
359 handle_gns_result_iter (void *cls,
361 const struct GNUNET_GNSRECORD_Data *rd)
363 struct IteratorHandle *ith = cls;
364 struct ReverseRecordEntry *rr;
365 gns_lookup_reverse = NULL;
366 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
367 "GNS for REVERSE (%s)\n", mynick);
370 if ((rd_count != 1) ||
371 (GNUNET_GNSRECORD_TYPE_PKEY != rd->record_type))
373 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
374 "GNS invalid REVERSE (%s)\n", mynick);
375 gns_lookup_reverse = NULL;
376 it_task = GNUNET_SCHEDULER_add_now (&next_it, ith);
381 rr = GNUNET_new (struct ReverseRecordEntry);
382 rr->record_len = sizeof (struct GNUNET_GNSRECORD_ReverseRecord)
383 + strlen (mynick) + 1;
384 rr->record = GNUNET_malloc (rr->record_len);
385 rr->record->pkey = ith->target;
386 rr->record->expiration.abs_value_us = rd->expiration_time;
387 GNUNET_memcpy ((char*)&rr->record[1],
390 GNUNET_CONTAINER_DLL_insert (ith->records_head,
394 it_task = GNUNET_SCHEDULER_add_now (&next_it, ith);
402 GNUNET_assert (NULL != namestore_iter);
403 GNUNET_NAMESTORE_zone_iterator_next (namestore_iter);
408 iterator_cb (void *cls,
409 const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
411 unsigned int rd_count,
412 const struct GNUNET_GNSRECORD_Data *rd)
414 struct IteratorHandle *ith = cls;
415 struct GNUNET_CRYPTO_EcdsaPublicKey zone;
418 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
419 "iterating for REVERSE (%s / %s)\n",
424 if ((rd_count != 1) ||
425 (GNUNET_GNSRECORD_TYPE_PKEY != rd->record_type))
427 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
428 "wrong format (%s)\n", mynick);
431 it_task = GNUNET_SCHEDULER_add_now (&next_it, ith);
434 GNUNET_CRYPTO_ecdsa_key_get_public (key,
436 if (0 != memcmp (&zone, &myzone,
437 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
439 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
440 "wrong zone (%s)\n", mynick);
443 it_task = GNUNET_SCHEDULER_add_now (&next_it, ith);
446 ith->target = *((struct GNUNET_CRYPTO_EcdsaPublicKey *) rd->data);
447 GNUNET_asprintf (&name,
450 gns_lookup_reverse = GNS_resolver_lookup (&ith->target,
451 GNUNET_GNSRECORD_TYPE_PKEY,
454 GNUNET_GNS_LO_DEFAULT,
455 &handle_gns_result_iter,
460 static void check_reverse_records (void *cls);
463 store_reverse (void *cls,
467 struct IteratorHandle *ith = cls;
468 struct ReverseRecordEntry *rr;
470 if (GNUNET_SYSERR == success)
472 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
476 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stored records (%s)\n", mynick);
478 for (rr = ith->records_head; NULL != rr; rr = ith->records_head)
480 GNUNET_CONTAINER_DLL_remove (ith->records_head,
483 GNUNET_free (rr->record);
486 reverse_record_check_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_DAYS,
487 &check_reverse_records,
494 finished_cb (void *cls)
496 struct IteratorHandle *ith = cls;
497 struct ReverseRecordEntry *rr;
498 struct GNUNET_GNSRECORD_Data rd[ith->record_count];
500 memset (rd, 0, sizeof (struct GNUNET_GNSRECORD_Data) * ith->record_count);
502 rr = ith->records_head;
503 for (int i = 0; i < ith->record_count; i++)
505 rd[i].data_size = rr->record_len;
506 rd[i].data = GNUNET_malloc (rr->record_len);
507 rd[i].record_type = GNUNET_GNSRECORD_TYPE_REVERSE;
508 rd[i].expiration_time = rr->record->expiration.abs_value_us;
509 GNUNET_memcpy ((char*) rd[i].data,
514 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
515 "Finished iterating for REVERSE\n");
517 ith->ns_qe = GNUNET_NAMESTORE_records_store (ns,
524 namestore_iter = NULL;
532 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
533 "Error iterating for REVERSE\n");
538 check_reverse_records (void *cls)
540 struct IteratorHandle *ith;
541 ith = GNUNET_new (struct IteratorHandle);
542 ith->record_count = 0;
543 reverse_record_check_task = NULL;
544 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
545 "Start iterating for REVERSE (%s)\n", mynick);
546 namestore_iter = GNUNET_NAMESTORE_zone_iteration_start (ns,
558 * Initialize reverser
560 * @param nh handle to a namestore
561 * @param key the private key of the gns-reverse zone
562 * @param name the name of the gns-reverse zone
566 GNS_reverse_init (struct GNUNET_NAMESTORE_Handle *nh,
567 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
570 GNUNET_asprintf (&mynick,
573 GNUNET_CRYPTO_ecdsa_key_get_public (zone,
575 GNUNET_memcpy (&pzone,
577 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
579 reverse_record_check_task = GNUNET_SCHEDULER_add_now (&check_reverse_records,
591 GNUNET_free (mynick);
593 GNUNET_SCHEDULER_cancel (it_task);
594 if (NULL != reverse_record_check_task)
595 GNUNET_SCHEDULER_cancel (reverse_record_check_task);
596 if (NULL != gns_lookup_reverse)
597 GNS_resolver_lookup_cancel (gns_lookup_reverse);
598 if (NULL != namestore_iter)
599 GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);