aboutsummaryrefslogtreecommitdiff
path: root/src/namecache/namecache_api.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2013-10-16 19:32:52 +0000
committerChristian Grothoff <christian@grothoff.org>2013-10-16 19:32:52 +0000
commit6308c2556c54ea8a19b33bfe16bd2f81eae65e86 (patch)
tree2017381fa55744868e3664b59a46d60cce8c2433 /src/namecache/namecache_api.c
parente71d2567fc6d2634c503587ba481cc92f5f5e60e (diff)
downloadgnunet-6308c2556c54ea8a19b33bfe16bd2f81eae65e86.tar.gz
gnunet-6308c2556c54ea8a19b33bfe16bd2f81eae65e86.zip
-copied block-related functions from namestore to namecache
Diffstat (limited to 'src/namecache/namecache_api.c')
-rw-r--r--src/namecache/namecache_api.c738
1 files changed, 738 insertions, 0 deletions
diff --git a/src/namecache/namecache_api.c b/src/namecache/namecache_api.c
new file mode 100644
index 000000000..a28ed7d53
--- /dev/null
+++ b/src/namecache/namecache_api.c
@@ -0,0 +1,738 @@
1/*
2 This file is part of GNUnet.
3 (C) 2010-2013 Christian Grothoff (and other contributing authors)
4
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.
9
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.
14
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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file namecache/namecache_api.c
23 * @brief API to access the NAMECACHE service
24 * @author Martin Schanzenbach
25 * @author Matthias Wachs
26 * @author Christian Grothoff
27 */
28
29#include "platform.h"
30#include "gnunet_util_lib.h"
31#include "gnunet_crypto_lib.h"
32#include "gnunet_constants.h"
33#include "gnunet_dnsparser_lib.h"
34#include "gnunet_arm_service.h"
35#include "gnunet_signatures.h"
36#include "gnunet_namecache_service.h"
37#include "gnunet_namestore_service.h"
38#include "namecache.h"
39
40
41#define LOG(kind,...) GNUNET_log_from (kind, "namecache-api",__VA_ARGS__)
42
43
44/**
45 * An QueueEntry used to store information for a pending
46 * NAMECACHE record operation
47 */
48struct GNUNET_NAMECACHE_QueueEntry
49{
50
51 /**
52 * Kept in a DLL.
53 */
54 struct GNUNET_NAMECACHE_QueueEntry *next;
55
56 /**
57 * Kept in a DLL.
58 */
59 struct GNUNET_NAMECACHE_QueueEntry *prev;
60
61 /**
62 * Main handle to access the namecache.
63 */
64 struct GNUNET_NAMECACHE_Handle *nsh;
65
66 /**
67 * Continuation to call
68 */
69 GNUNET_NAMECACHE_ContinuationWithStatus cont;
70
71 /**
72 * Closure for @e cont.
73 */
74 void *cont_cls;
75
76 /**
77 * Function to call with the blocks we get back; or NULL.
78 */
79 GNUNET_NAMESTORE_BlockProcessor block_proc;
80
81 /**
82 * Closure for @e block_proc.
83 */
84 void *block_proc_cls;
85
86 /**
87 * The operation id this zone iteration operation has
88 */
89 uint32_t op_id;
90
91};
92
93
94/**
95 * Message in linked list we should send to the service. The
96 * actual binary message follows this struct.
97 */
98struct PendingMessage
99{
100
101 /**
102 * Kept in a DLL.
103 */
104 struct PendingMessage *next;
105
106 /**
107 * Kept in a DLL.
108 */
109 struct PendingMessage *prev;
110
111 /**
112 * Size of the message.
113 */
114 size_t size;
115
116};
117
118
119/**
120 * Connection to the NAMECACHE service.
121 */
122struct GNUNET_NAMECACHE_Handle
123{
124
125 /**
126 * Configuration to use.
127 */
128 const struct GNUNET_CONFIGURATION_Handle *cfg;
129
130 /**
131 * Socket (if available).
132 */
133 struct GNUNET_CLIENT_Connection *client;
134
135 /**
136 * Currently pending transmission request (or NULL).
137 */
138 struct GNUNET_CLIENT_TransmitHandle *th;
139
140 /**
141 * Head of linked list of pending messages to send to the service
142 */
143 struct PendingMessage *pending_head;
144
145 /**
146 * Tail of linked list of pending messages to send to the service
147 */
148 struct PendingMessage *pending_tail;
149
150 /**
151 * Head of pending namecache queue entries
152 */
153 struct GNUNET_NAMECACHE_QueueEntry *op_head;
154
155 /**
156 * Tail of pending namecache queue entries
157 */
158 struct GNUNET_NAMECACHE_QueueEntry *op_tail;
159
160 /**
161 * Reconnect task
162 */
163 GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
164
165 /**
166 * Delay introduced before we reconnect.
167 */
168 struct GNUNET_TIME_Relative reconnect_delay;
169
170 /**
171 * Should we reconnect to service due to some serious error?
172 */
173 int reconnect;
174
175 /**
176 * Did we start to receive yet?
177 */
178 int is_receiving;
179
180 /**
181 * The last operation id used for a NAMECACHE operation
182 */
183 uint32_t last_op_id_used;
184
185};
186
187
188/**
189 * Disconnect from service and then reconnect.
190 *
191 * @param h our handle
192 */
193static void
194force_reconnect (struct GNUNET_NAMECACHE_Handle *h);
195
196
197/**
198 * Handle an incoming message of type
199 * #GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE.
200 *
201 * @param qe the respective entry in the message queue
202 * @param msg the message we received
203 * @param size the message size
204 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error and we did NOT notify the client
205 */
206static int
207handle_lookup_block_response (struct GNUNET_NAMECACHE_QueueEntry *qe,
208 const struct LookupBlockResponseMessage *msg,
209 size_t size)
210{
211 struct GNUNET_NAMESTORE_Block *block;
212 char buf[size + sizeof (struct GNUNET_NAMESTORE_Block)
213 - sizeof (struct LookupBlockResponseMessage)];
214
215 LOG (GNUNET_ERROR_TYPE_DEBUG,
216 "Received `%s'\n",
217 "LOOKUP_BLOCK_RESPONSE");
218 if (0 == GNUNET_TIME_absolute_ntoh (msg->expire).abs_value_us)
219 {
220 /* no match found */
221 if (NULL != qe->block_proc)
222 qe->block_proc (qe->block_proc_cls, NULL);
223 return GNUNET_OK;
224 }
225
226 block = (struct GNUNET_NAMESTORE_Block *) buf;
227 block->signature = msg->signature;
228 block->derived_key = msg->derived_key;
229 block->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN);
230 block->purpose.size = htonl (size - sizeof (struct LookupBlockResponseMessage) +
231 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
232 sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose));
233 block->expiration_time = msg->expire;
234 memcpy (&block[1],
235 &msg[1],
236 size - sizeof (struct LookupBlockResponseMessage));
237 if (GNUNET_OK !=
238 GNUNET_NAMESTORE_block_verify (block))
239 {
240 GNUNET_break (0);
241 return GNUNET_SYSERR;
242 }
243 if (NULL != qe->block_proc)
244 qe->block_proc (qe->block_proc_cls, block);
245 else
246 GNUNET_break (0);
247 return GNUNET_OK;
248}
249
250
251/**
252 * Handle an incoming message of type
253 * #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE_RESPONSE
254 *
255 * @param qe the respective entry in the message queue
256 * @param msg the message we received
257 * @param size the message size
258 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error and we did NOT notify the client
259 */
260static int
261handle_block_cache_response (struct GNUNET_NAMECACHE_QueueEntry *qe,
262 const struct BlockCacheResponseMessage *msg,
263 size_t size)
264{
265 int res;
266
267 LOG (GNUNET_ERROR_TYPE_DEBUG,
268 "Received `%s'\n",
269 "BLOCK_CACHE_RESPONSE");
270 res = ntohl (msg->op_result);
271 /* TODO: add actual error message from namecache to response... */
272 if (NULL != qe->cont)
273 qe->cont (qe->cont_cls,
274 res,
275 (GNUNET_OK == res) ?
276 NULL
277 : _("Namecache failed to cache block"));
278 return GNUNET_OK;
279}
280
281
282/**
283 * Handle incoming messages for record operations
284 *
285 * @param qe the respective zone iteration handle
286 * @param msg the message we received
287 * @param type the message type in host byte order
288 * @param size the message size
289 * @return #GNUNET_OK on success, #GNUNET_NO if we notified the client about
290 * the error, #GNUNET_SYSERR on error and we did NOT notify the client
291 */
292static int
293manage_record_operations (struct GNUNET_NAMECACHE_QueueEntry *qe,
294 const struct GNUNET_MessageHeader *msg,
295 uint16_t type,
296 size_t size)
297{
298 /* handle different message type */
299 switch (type)
300 {
301 case GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE:
302 if (size < sizeof (struct LookupBlockResponseMessage))
303 {
304 GNUNET_break (0);
305 return GNUNET_SYSERR;
306 }
307 return handle_lookup_block_response (qe, (const struct LookupBlockResponseMessage *) msg, size);
308 case GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE_RESPONSE:
309 if (size != sizeof (struct BlockCacheResponseMessage))
310 {
311 GNUNET_break (0);
312 return GNUNET_SYSERR;
313 }
314 return handle_block_cache_response (qe, (const struct BlockCacheResponseMessage *) msg, size);
315 default:
316 GNUNET_break (0);
317 return GNUNET_SYSERR;
318 }
319}
320
321
322/**
323 * Type of a function to call when we receive a message
324 * from the service.
325 *
326 * @param cls the `struct GNUNET_NAMECACHE_SchedulingHandle`
327 * @param msg message received, NULL on timeout or fatal error
328 */
329static void
330process_namecache_message (void *cls,
331 const struct GNUNET_MessageHeader *msg)
332{
333 struct GNUNET_NAMECACHE_Handle *h = cls;
334 const struct GNUNET_NAMECACHE_Header *gm;
335 struct GNUNET_NAMECACHE_QueueEntry *qe;
336 uint16_t size;
337 uint16_t type;
338 uint32_t r_id;
339 int ret;
340
341 if (NULL == msg)
342 {
343 force_reconnect (h);
344 return;
345 }
346 size = ntohs (msg->size);
347 type = ntohs (msg->type);
348 if (size < sizeof (struct GNUNET_NAMECACHE_Header))
349 {
350 GNUNET_break_op (0);
351 GNUNET_CLIENT_receive (h->client,
352 &process_namecache_message, h,
353 GNUNET_TIME_UNIT_FOREVER_REL);
354 return;
355 }
356 gm = (const struct GNUNET_NAMECACHE_Header *) msg;
357 r_id = ntohl (gm->r_id);
358
359 LOG (GNUNET_ERROR_TYPE_DEBUG,
360 "Received message type %u size %u op %u\n",
361 (unsigned int) type,
362 (unsigned int) size,
363 (unsigned int) r_id);
364
365 /* Is it a record related operation ? */
366 for (qe = h->op_head; qe != NULL; qe = qe->next)
367 if (qe->op_id == r_id)
368 break;
369 if (NULL != qe)
370 {
371 ret = manage_record_operations (qe, msg, type, size);
372 if (GNUNET_SYSERR == ret)
373 {
374 /* protocol error, need to reconnect */
375 h->reconnect = GNUNET_YES;
376 }
377 else
378 {
379 /* client was notified about success or failure, clean up 'qe' */
380 GNUNET_CONTAINER_DLL_remove (h->op_head,
381 h->op_tail,
382 qe);
383 GNUNET_free (qe);
384 }
385 }
386 if (GNUNET_YES == h->reconnect)
387 {
388 force_reconnect (h);
389 return;
390 }
391 GNUNET_CLIENT_receive (h->client, &process_namecache_message, h,
392 GNUNET_TIME_UNIT_FOREVER_REL);
393}
394
395
396/**
397 * Transmit messages from the message queue to the service
398 * (if there are any, and if we are not already trying).
399 *
400 * @param h handle to use
401 */
402static void
403do_transmit (struct GNUNET_NAMECACHE_Handle *h);
404
405
406/**
407 * We can now transmit a message to NAMECACHE. Do it.
408 *
409 * @param cls the `struct GNUNET_NAMECACHE_Handle`
410 * @param size number of bytes we can transmit
411 * @param buf where to copy the messages
412 * @return number of bytes copied into @a buf
413 */
414static size_t
415transmit_message_to_namecache (void *cls,
416 size_t size,
417 void *buf)
418{
419 struct GNUNET_NAMECACHE_Handle *h = cls;
420 struct PendingMessage *p;
421 size_t ret;
422 char *cbuf;
423
424 h->th = NULL;
425 if ((0 == size) || (NULL == buf))
426 {
427 force_reconnect (h);
428 return 0;
429 }
430 ret = 0;
431 cbuf = buf;
432 while ( (NULL != (p = h->pending_head)) &&
433 (p->size <= size) )
434 {
435 memcpy (&cbuf[ret], &p[1], p->size);
436 ret += p->size;
437 size -= p->size;
438 GNUNET_CONTAINER_DLL_remove (h->pending_head,
439 h->pending_tail,
440 p);
441 if (GNUNET_NO == h->is_receiving)
442 {
443 h->is_receiving = GNUNET_YES;
444 GNUNET_CLIENT_receive (h->client,
445 &process_namecache_message, h,
446 GNUNET_TIME_UNIT_FOREVER_REL);
447 }
448 GNUNET_free (p);
449 }
450 do_transmit (h);
451 return ret;
452}
453
454
455/**
456 * Transmit messages from the message queue to the service
457 * (if there are any, and if we are not already trying).
458 *
459 * @param h handle to use
460 */
461static void
462do_transmit (struct GNUNET_NAMECACHE_Handle *h)
463{
464 struct PendingMessage *p;
465
466 if (NULL != h->th)
467 return; /* transmission request already pending */
468 if (NULL == (p = h->pending_head))
469 return; /* transmission queue empty */
470 if (NULL == h->client)
471 return; /* currently reconnecting */
472 h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, p->size,
473 GNUNET_TIME_UNIT_FOREVER_REL,
474 GNUNET_NO, &transmit_message_to_namecache,
475 h);
476 GNUNET_break (NULL != h->th);
477}
478
479
480/**
481 * Reconnect to namecache service.
482 *
483 * @param h the handle to the NAMECACHE service
484 */
485static void
486reconnect (struct GNUNET_NAMECACHE_Handle *h)
487{
488 GNUNET_assert (NULL == h->client);
489 h->client = GNUNET_CLIENT_connect ("namecache", h->cfg);
490 GNUNET_assert (NULL != h->client);
491 do_transmit (h);
492}
493
494
495/**
496 * Re-establish the connection to the service.
497 *
498 * @param cls handle to use to re-connect.
499 * @param tc scheduler context
500 */
501static void
502reconnect_task (void *cls,
503 const struct GNUNET_SCHEDULER_TaskContext *tc)
504{
505 struct GNUNET_NAMECACHE_Handle *h = cls;
506
507 h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
508 reconnect (h);
509}
510
511
512/**
513 * Disconnect from service and then reconnect.
514 *
515 * @param h our handle
516 */
517static void
518force_reconnect (struct GNUNET_NAMECACHE_Handle *h)
519{
520 if (NULL != h->th)
521 {
522 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
523 h->th = NULL;
524 }
525 h->reconnect = GNUNET_NO;
526 GNUNET_CLIENT_disconnect (h->client);
527 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
528 "Reconnecting to namecache\n");
529 h->is_receiving = GNUNET_NO;
530 h->client = NULL;
531 h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
532 h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_delay,
533 &reconnect_task,
534 h);
535}
536
537
538/**
539 * Get a fresh operation id to distinguish between namecache requests
540 *
541 * @param h the namecache handle
542 * @return next operation id to use
543 */
544static uint32_t
545get_op_id (struct GNUNET_NAMECACHE_Handle *h)
546{
547 return h->last_op_id_used++;
548}
549
550
551/**
552 * Initialize the connection with the NAMECACHE service.
553 *
554 * @param cfg configuration to use
555 * @return handle to the GNS service, or NULL on error
556 */
557struct GNUNET_NAMECACHE_Handle *
558GNUNET_NAMECACHE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
559{
560 struct GNUNET_NAMECACHE_Handle *h;
561
562 h = GNUNET_new (struct GNUNET_NAMECACHE_Handle);
563 h->cfg = cfg;
564 h->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect_task, h);
565 h->last_op_id_used = 0;
566 return h;
567}
568
569
570/**
571 * Disconnect from the namecache service (and free associated
572 * resources).
573 *
574 * @param h handle to the namecache
575 */
576void
577GNUNET_NAMECACHE_disconnect (struct GNUNET_NAMECACHE_Handle *h)
578{
579 struct PendingMessage *p;
580 struct GNUNET_NAMECACHE_QueueEntry *q;
581
582 LOG (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
583 GNUNET_assert (NULL != h);
584 if (NULL != h->th)
585 {
586 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
587 h->th = NULL;
588 }
589 while (NULL != (p = h->pending_head))
590 {
591 GNUNET_CONTAINER_DLL_remove (h->pending_head, h->pending_tail, p);
592 GNUNET_free (p);
593 }
594 GNUNET_break (NULL == h->op_head);
595 while (NULL != (q = h->op_head))
596 {
597 GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, q);
598 GNUNET_free (q);
599 }
600 if (NULL != h->client)
601 {
602 GNUNET_CLIENT_disconnect (h->client);
603 h->client = NULL;
604 }
605 if (GNUNET_SCHEDULER_NO_TASK != h->reconnect_task)
606 {
607 GNUNET_SCHEDULER_cancel (h->reconnect_task);
608 h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
609 }
610 GNUNET_free (h);
611}
612
613
614/**
615 * Store an item in the namecache. If the item is already present,
616 * it is replaced with the new record.
617 *
618 * @param h handle to the namecache
619 * @param block block to store
620 * @param cont continuation to call when done
621 * @param cont_cls closure for cont
622 * @return handle to abort the request
623 */
624struct GNUNET_NAMECACHE_QueueEntry *
625GNUNET_NAMECACHE_block_cache (struct GNUNET_NAMECACHE_Handle *h,
626 const struct GNUNET_NAMESTORE_Block *block,
627 GNUNET_NAMECACHE_ContinuationWithStatus cont,
628 void *cont_cls)
629{
630 struct GNUNET_NAMECACHE_QueueEntry *qe;
631 struct PendingMessage *pe;
632 struct BlockCacheMessage *msg;
633 uint32_t rid;
634 size_t blen;
635 size_t msg_size;
636
637 GNUNET_assert (NULL != h);
638 blen = ntohl (block->purpose.size)
639 - sizeof (struct GNUNET_TIME_AbsoluteNBO)
640 - sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose);
641 rid = get_op_id (h);
642 qe = GNUNET_new (struct GNUNET_NAMECACHE_QueueEntry);
643 qe->nsh = h;
644 qe->cont = cont;
645 qe->cont_cls = cont_cls;
646 qe->op_id = rid;
647 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, qe);
648
649 /* setup msg */
650 msg_size = sizeof (struct BlockCacheMessage) + blen;
651 pe = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size);
652 pe->size = msg_size;
653 msg = (struct BlockCacheMessage *) &pe[1];
654 msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE);
655 msg->gns_header.header.size = htons (msg_size);
656 msg->gns_header.r_id = htonl (rid);
657 msg->expire = block->expiration_time;
658 msg->signature = block->signature;
659 msg->derived_key = block->derived_key;
660 memcpy (&msg[1], &block[1], blen);
661 LOG (GNUNET_ERROR_TYPE_DEBUG,
662 "Sending `%s' message with size %u and expiration %s\n",
663 "NAMECACHE_BLOCK_CACHE",
664 (unsigned int) msg_size,
665 GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (msg->expire)));
666 GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe);
667 do_transmit (h);
668 return qe;
669}
670
671
672/**
673 * Get a result for a particular key from the namecache. The processor
674 * will only be called once.
675 *
676 * @param h handle to the namecache
677 * @param derived_hash hash of zone key combined with name to lookup
678 * @param proc function to call on the matching block, or with
679 * NULL if there is no matching block
680 * @param proc_cls closure for proc
681 * @return a handle that can be used to cancel
682 */
683struct GNUNET_NAMECACHE_QueueEntry *
684GNUNET_NAMECACHE_lookup_block (struct GNUNET_NAMECACHE_Handle *h,
685 const struct GNUNET_HashCode *derived_hash,
686 GNUNET_NAMESTORE_BlockProcessor proc, void *proc_cls)
687{
688 struct GNUNET_NAMECACHE_QueueEntry *qe;
689 struct PendingMessage *pe;
690 struct LookupBlockMessage *msg;
691 size_t msg_size;
692 uint32_t rid;
693
694 GNUNET_assert (NULL != h);
695 GNUNET_assert (NULL != derived_hash);
696 LOG (GNUNET_ERROR_TYPE_DEBUG,
697 "Looking for block under %s\n",
698 GNUNET_h2s (derived_hash));
699 rid = get_op_id(h);
700 qe = GNUNET_new (struct GNUNET_NAMECACHE_QueueEntry);
701 qe->nsh = h;
702 qe->block_proc = proc;
703 qe->block_proc_cls = proc_cls;
704 qe->op_id = rid;
705 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, qe);
706
707 msg_size = sizeof (struct LookupBlockMessage);
708 pe = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size);
709 pe->size = msg_size;
710 msg = (struct LookupBlockMessage *) &pe[1];
711 msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK);
712 msg->gns_header.header.size = htons (msg_size);
713 msg->gns_header.r_id = htonl (rid);
714 msg->query = *derived_hash;
715 GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe);
716 do_transmit (h);
717 return qe;
718}
719
720
721/**
722 * Cancel a namecache operation. The final callback from the
723 * operation must not have been done yet.
724 *
725 * @param qe operation to cancel
726 */
727void
728GNUNET_NAMECACHE_cancel (struct GNUNET_NAMECACHE_QueueEntry *qe)
729{
730 struct GNUNET_NAMECACHE_Handle *h = qe->nsh;
731
732 GNUNET_assert (NULL != qe);
733 GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, qe);
734 GNUNET_free(qe);
735}
736
737
738/* end of namecache_api.c */