caching test
[oweals/gnunet.git] / src / namestore / namestore_api.c
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 namestore/namestore_api.c
23  * @brief API to access the NAMESTORE 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_namestore_service.h"
37 #include "namestore.h"
38
39
40 #define LOG(kind,...) GNUNET_log_from (kind, "namestore-api",__VA_ARGS__)
41
42
43 /**
44  * An QueueEntry used to store information for a pending
45  * NAMESTORE record operation
46  */
47 struct GNUNET_NAMESTORE_QueueEntry
48 {
49
50   /**
51    * Kept in a DLL.
52    */
53   struct GNUNET_NAMESTORE_QueueEntry *next;
54
55   /**
56    * Kept in a DLL.
57    */
58   struct GNUNET_NAMESTORE_QueueEntry *prev;
59
60   /**
61    * Main handle to access the namestore.
62    */
63   struct GNUNET_NAMESTORE_Handle *nsh;
64
65   /**
66    * Continuation to call
67    */
68   GNUNET_NAMESTORE_ContinuationWithStatus cont;
69
70   /**
71    * Closure for 'cont'.
72    */
73   void *cont_cls;
74
75   /**
76    * Function to call with the records we get back; or NULL.
77    */
78   GNUNET_NAMESTORE_RecordMonitor proc;
79
80   /**
81    * Closure for @e proc.
82    */
83   void *proc_cls;
84
85   /**
86    * Function to call with the blocks we get back; or NULL.
87    */
88   GNUNET_NAMESTORE_BlockProcessor block_proc;
89
90   /**
91    * Closure for @e block_proc.
92    */
93   void *block_proc_cls;
94
95   /**
96    * The operation id this zone iteration operation has
97    */
98   uint32_t op_id;
99
100 };
101
102
103 /**
104  * Handle for a zone iterator operation
105  */
106 struct GNUNET_NAMESTORE_ZoneIterator
107 {
108
109   /**
110    * Kept in a DLL.
111    */
112   struct GNUNET_NAMESTORE_ZoneIterator *next;
113
114   /**
115    * Kept in a DLL.
116    */
117   struct GNUNET_NAMESTORE_ZoneIterator *prev;
118
119   /**
120    * Main handle to access the namestore.
121    */
122   struct GNUNET_NAMESTORE_Handle *h;
123
124   /**
125    * The continuation to call with the results
126    */
127   GNUNET_NAMESTORE_RecordMonitor proc;
128
129   /**
130    * Closure for @e proc.
131    */
132   void* proc_cls;
133
134   /**
135    * Private key of the zone.
136    */
137   struct GNUNET_CRYPTO_EccPrivateKey zone;
138
139   /**
140    * The operation id this zone iteration operation has
141    */
142   uint32_t op_id;
143
144 };
145
146
147 /**
148  * Message in linked list we should send to the service.  The
149  * actual binary message follows this struct.
150  */
151 struct PendingMessage
152 {
153
154   /**
155    * Kept in a DLL.
156    */
157   struct PendingMessage *next;
158
159   /**
160    * Kept in a DLL.
161    */
162   struct PendingMessage *prev;
163
164   /**
165    * Size of the message.
166    */
167   size_t size;
168
169 };
170
171
172 /**
173  * Connection to the NAMESTORE service.
174  */
175 struct GNUNET_NAMESTORE_Handle
176 {
177
178   /**
179    * Configuration to use.
180    */
181   const struct GNUNET_CONFIGURATION_Handle *cfg;
182
183   /**
184    * Socket (if available).
185    */
186   struct GNUNET_CLIENT_Connection *client;
187
188   /**
189    * Currently pending transmission request (or NULL).
190    */
191   struct GNUNET_CLIENT_TransmitHandle *th;
192
193   /**
194    * Head of linked list of pending messages to send to the service
195    */
196   struct PendingMessage *pending_head;
197
198   /**
199    * Tail of linked list of pending messages to send to the service
200    */
201   struct PendingMessage *pending_tail;
202
203   /**
204    * Head of pending namestore queue entries
205    */
206   struct GNUNET_NAMESTORE_QueueEntry *op_head;
207
208   /**
209    * Tail of pending namestore queue entries
210    */
211   struct GNUNET_NAMESTORE_QueueEntry *op_tail;
212
213   /**
214    * Head of pending namestore zone iterator entries
215    */
216   struct GNUNET_NAMESTORE_ZoneIterator *z_head;
217
218   /**
219    * Tail of pending namestore zone iterator entries
220    */
221   struct GNUNET_NAMESTORE_ZoneIterator *z_tail;
222
223   /**
224    * Reconnect task
225    */
226   GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
227
228   /**
229    * Should we reconnect to service due to some serious error?
230    */
231   int reconnect;
232
233   /**
234    * Did we start to receive yet?
235    */
236   int is_receiving;
237
238   /**
239    * The last operation id used for a NAMESTORE operation
240    */
241   uint32_t last_op_id_used;
242
243 };
244
245
246 /**
247  * Disconnect from service and then reconnect.
248  *
249  * @param h our handle
250  */
251 static void
252 force_reconnect (struct GNUNET_NAMESTORE_Handle *h);
253
254
255 /**
256  * Handle an incoming message of type
257  * #GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_BLOCK_RESPONSE.
258  *
259  * @param qe the respective entry in the message queue
260  * @param msg the message we received
261  * @param size the message size
262  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error and we did NOT notify the client
263  */
264 static int
265 handle_lookup_block_response (struct GNUNET_NAMESTORE_QueueEntry *qe,
266                               const struct LookupBlockResponseMessage *msg,
267                               size_t size)
268 {
269   struct GNUNET_NAMESTORE_Block *block;
270   char buf[size + sizeof (struct GNUNET_NAMESTORE_Block) 
271            - sizeof (struct LookupBlockResponseMessage)];
272
273   LOG (GNUNET_ERROR_TYPE_DEBUG,
274        "Received `%s'\n", 
275        "LOOKUP_BLOCK_RESPONSE");
276   if (0 == GNUNET_TIME_absolute_ntoh (msg->expire).abs_value_us)
277   {
278     /* no match found */
279     if (NULL != qe->block_proc)
280       qe->block_proc (qe->block_proc_cls, NULL);
281     return GNUNET_OK;
282   }
283
284   block = (struct GNUNET_NAMESTORE_Block *) buf;
285   block->signature = msg->signature;
286   block->derived_key = msg->derived_key;
287   block->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN);
288   block->purpose.size = htonl (size - sizeof (struct LookupBlockResponseMessage) + 
289                                sizeof (struct GNUNET_TIME_AbsoluteNBO) +
290                                sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose));
291   block->expiration_time = msg->expire;
292   memcpy (&block[1],
293           &msg[1],
294           size - sizeof (struct LookupBlockResponseMessage));
295   if (GNUNET_OK !=
296       GNUNET_NAMESTORE_block_verify (block))
297   {
298     GNUNET_break (0);
299     return GNUNET_SYSERR;
300   }
301   if (NULL != qe->block_proc)
302     qe->block_proc (qe->block_proc_cls, block);
303   else
304     GNUNET_break (0);
305   return GNUNET_OK;
306 }
307
308
309 /**
310  * Handle an incoming message of type
311  * #GNUNET_MESSAGE_TYPE_NAMESTORE_BLOCK_CACHE_RESPONSE
312  *
313  * @param qe the respective entry in the message queue
314  * @param msg the message we received
315  * @param size the message size
316  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error and we did NOT notify the client
317  */
318 static int
319 handle_block_cache_response (struct GNUNET_NAMESTORE_QueueEntry *qe,
320                             const struct BlockCacheResponseMessage *msg,
321                             size_t size)
322 {
323   int res;
324
325   LOG (GNUNET_ERROR_TYPE_DEBUG,
326        "Received `%s'\n",
327        "BLOCK_CACHE_RESPONSE");
328   res = ntohl (msg->op_result);
329   /* TODO: add actual error message from namestore to response... */
330   if (NULL != qe->cont)    
331     qe->cont (qe->cont_cls, 
332               res, 
333               (GNUNET_OK == res) ? 
334               NULL 
335               : _("Namestore failed to cache block"));
336   return GNUNET_OK;
337 }
338
339
340 /**
341  * Handle an incoming message of type
342  * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE
343  *
344  * @param qe the respective entry in the message queue
345  * @param msg the message we received
346  * @param size the message size
347  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error and we did NOT notify the client
348  */
349 static int
350 handle_record_store_response (struct GNUNET_NAMESTORE_QueueEntry *qe,
351                               const struct RecordStoreResponseMessage* msg,
352                               size_t size)
353 {
354   int res;
355   const char *emsg;
356   
357   LOG (GNUNET_ERROR_TYPE_DEBUG, 
358        "Received `%s'\n",
359        "RECORD_STORE_RESPONSE");
360   /* TODO: add actual error message from namestore to response... */
361   res = ntohl (msg->op_result);
362   if (GNUNET_SYSERR == res)
363     emsg = _("Namestore failed to store record\n");
364   else
365     emsg = NULL;
366   if (NULL != qe->cont)    
367     qe->cont (qe->cont_cls, res, emsg);
368   return GNUNET_OK;
369 }
370
371
372 /**
373  * Handle an incoming message of type
374  * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT
375  *
376  * @param qe the respective entry in the message queue
377  * @param msg the message we received
378  * @param size the message size
379  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error and we did NOT notify the client
380  */
381 static int
382 handle_record_result (struct GNUNET_NAMESTORE_QueueEntry *qe,
383                       const struct RecordResultMessage *msg,
384                       size_t size)
385 {
386   const char *name;
387   const char *rd_tmp;
388   size_t exp_msg_len;
389   size_t msg_len;
390   size_t name_len;
391   size_t rd_len;
392   unsigned int rd_count;
393
394   LOG (GNUNET_ERROR_TYPE_DEBUG,
395        "Received `%s'\n", 
396        "RECORD_RESULT");
397   rd_len = ntohs (msg->rd_len);
398   rd_count = ntohs (msg->rd_count);
399   msg_len = ntohs (msg->gns_header.header.size);
400   name_len = ntohs (msg->name_len);
401   GNUNET_break (0 == ntohs (msg->reserved));
402   exp_msg_len = sizeof (struct RecordResultMessage) + name_len + rd_len;
403   if (msg_len != exp_msg_len)
404   {
405     GNUNET_break (0);
406     return GNUNET_SYSERR;
407   }
408   name = (const char *) &msg[1];
409   if ( (name_len > 0) &&
410        ('\0' != name[name_len -1]) )
411   {
412     GNUNET_break (0);
413     return GNUNET_SYSERR;
414   }
415   rd_tmp = &name[name_len];
416   {
417     struct GNUNET_NAMESTORE_RecordData rd[rd_count];
418
419     if (GNUNET_OK != GNUNET_NAMESTORE_records_deserialize(rd_len, rd_tmp, rd_count, rd))
420     {
421       GNUNET_break (0);
422       return GNUNET_SYSERR;
423     }
424     if (0 == name_len)
425       name = NULL;
426     if (NULL != qe->proc)
427       qe->proc (qe->proc_cls, 
428                 &msg->private_key,
429                 name,
430                 rd_count,
431                 (rd_count > 0) ? rd : NULL);      
432   }
433   return GNUNET_OK;
434 }
435
436
437 /**
438  * Handle an incoming message of type
439  * #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE.
440  *
441  * @param qe the respective entry in the message queue
442  * @param msg the message we received
443  * @param size the message size
444  * @return #GNUNET_OK on success, #GNUNET_NO if we notified the client about
445  *         the error, #GNUNET_SYSERR on error and we did NOT notify the client
446  */
447 static int
448 handle_zone_to_name_response (struct GNUNET_NAMESTORE_QueueEntry *qe,
449                               const struct ZoneToNameResponseMessage *msg,
450                               size_t size)
451 {
452   int res;
453   size_t name_len;
454   size_t rd_ser_len;
455   unsigned int rd_count;
456   const char *name_tmp;
457   const char *rd_tmp;
458
459   LOG (GNUNET_ERROR_TYPE_DEBUG, 
460        "Received `%s'\n",
461        "ZONE_TO_NAME_RESPONSE");
462   res = ntohs (msg->res);
463   switch (res)
464   {
465   case GNUNET_SYSERR:
466     LOG (GNUNET_ERROR_TYPE_DEBUG,
467          "An error occured during zone to name operation\n");
468     break;
469   case GNUNET_NO:
470     LOG (GNUNET_ERROR_TYPE_DEBUG, 
471          "Namestore has no result for zone to name mapping \n");
472     break;
473   case GNUNET_YES:
474     LOG (GNUNET_ERROR_TYPE_DEBUG, 
475          "Namestore has result for zone to name mapping \n");
476     name_len = ntohs (msg->name_len);
477     rd_count = ntohs (msg->rd_count);
478     rd_ser_len = ntohs (msg->rd_len);
479     name_tmp = (const char *) &msg[1];
480     if ( (name_len > 0) &&
481          ('\0' != name_tmp[name_len -1]) )
482     {
483       GNUNET_break (0);
484       return GNUNET_SYSERR;
485     }
486     rd_tmp = &name_tmp[name_len];
487     {
488       struct GNUNET_NAMESTORE_RecordData rd[rd_count];
489
490       if (GNUNET_OK != GNUNET_NAMESTORE_records_deserialize(rd_ser_len, rd_tmp, rd_count, rd))
491       {
492         GNUNET_break (0);
493         return GNUNET_SYSERR;
494       }
495       /* normal end, call continuation with result */
496       if (NULL != qe->proc)
497         qe->proc (qe->proc_cls, 
498                   &msg->zone,
499                   name_tmp, 
500                   rd_count, rd);           
501       /* return is important here: break would call continuation with error! */
502       return GNUNET_OK;
503     }
504   default:
505     GNUNET_break (0);
506     return GNUNET_SYSERR;
507   }
508   /* error case, call continuation with error */
509   if (NULL != qe->proc)
510     qe->proc (qe->proc_cls, NULL, NULL, 0, NULL);
511   return GNUNET_NO;
512 }
513
514
515 /**
516  * Handle incoming messages for record operations
517  *
518  * @param qe the respective zone iteration handle
519  * @param msg the message we received
520  * @param type the message type in host byte order
521  * @param size the message size
522  * @return #GNUNET_OK on success, #GNUNET_NO if we notified the client about
523  *         the error, #GNUNET_SYSERR on error and we did NOT notify the client
524  */
525 static int
526 manage_record_operations (struct GNUNET_NAMESTORE_QueueEntry *qe,
527                           const struct GNUNET_MessageHeader *msg,
528                           uint16_t type, 
529                           size_t size)
530 {
531   /* handle different message type */
532   switch (type) 
533   {
534   case GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_BLOCK_RESPONSE:
535     if (size < sizeof (struct LookupBlockResponseMessage))
536     {
537       GNUNET_break (0);
538       return GNUNET_SYSERR;
539     }
540     return handle_lookup_block_response (qe, (const struct LookupBlockResponseMessage *) msg, size);
541   case GNUNET_MESSAGE_TYPE_NAMESTORE_BLOCK_CACHE_RESPONSE:
542     if (size != sizeof (struct BlockCacheResponseMessage))
543     {
544       GNUNET_break (0);
545       return GNUNET_SYSERR;
546     }
547     return handle_block_cache_response (qe, (const struct BlockCacheResponseMessage *) msg, size);
548   case GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE:
549     if (size != sizeof (struct RecordStoreResponseMessage))
550     {
551       GNUNET_break (0);
552       return GNUNET_SYSERR;
553     }
554     return handle_record_store_response (qe, (const struct RecordStoreResponseMessage *) msg, size);
555   case GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE:
556     if (size < sizeof (struct ZoneToNameResponseMessage))
557     {
558       GNUNET_break (0);
559       return GNUNET_SYSERR;
560     }
561     return handle_zone_to_name_response (qe, (const struct ZoneToNameResponseMessage *) msg, size);
562   case GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT:
563     if (size < sizeof (struct RecordResultMessage))
564     {
565       GNUNET_break (0);
566       return GNUNET_SYSERR;
567     }
568     return handle_record_result (qe, (const struct RecordResultMessage *) msg, size);
569   default:
570     GNUNET_break (0);
571     return GNUNET_SYSERR;
572   }
573 }
574
575
576 /**
577  * Handle a response from NAMESTORE service for a zone iteration request
578  *
579  * @param ze the respective iterator for this operation
580  * @param msg the message containing the respoonse
581  * @param size the message size
582  * @return #GNUNET_YES on success, @a ze should be kept, #GNUNET_NO on success if @a ze should
583  *         not be kept any longer, #GNUNET_SYSERR on error (disconnect) and @a ze should be kept
584  */
585 static int
586 handle_zone_iteration_response (struct GNUNET_NAMESTORE_ZoneIterator *ze,
587                                 const struct RecordResultMessage *msg,
588                                 size_t size)
589 {
590   static struct GNUNET_CRYPTO_EccPrivateKey priv_dummy;
591   size_t msg_len;
592   size_t exp_msg_len;
593   size_t name_len;
594   size_t rd_len;
595   unsigned rd_count;
596   const char *name_tmp;
597   const char *rd_ser_tmp;
598
599   LOG (GNUNET_ERROR_TYPE_DEBUG, 
600        "Received `%s'\n",
601        "ZONE_ITERATION_RESPONSE");
602   msg_len = ntohs (msg->gns_header.header.size);
603   rd_len = ntohs (msg->rd_len);
604   rd_count = ntohs (msg->rd_count);
605   name_len = ntohs (msg->name_len);
606   exp_msg_len = sizeof (struct RecordResultMessage) + name_len + rd_len;
607   if (msg_len != exp_msg_len)
608   {
609     GNUNET_break (0);
610     return GNUNET_SYSERR;
611   }
612   if ( (0 == name_len) && 
613        (0 == (memcmp (&msg->private_key, 
614                       &priv_dummy,
615                       sizeof (priv_dummy)))) )
616   {
617     LOG (GNUNET_ERROR_TYPE_DEBUG,
618          "Zone iteration completed!\n");
619     if (NULL != ze->proc)
620       ze->proc (ze->proc_cls, NULL, NULL, 0, NULL);
621     return GNUNET_NO;
622   }
623   name_tmp = (const char *) &msg[1];
624   if ((name_tmp[name_len -1] != '\0') || (name_len > MAX_NAME_LEN))
625   {
626     GNUNET_break (0);
627     return GNUNET_SYSERR;
628   }
629   rd_ser_tmp = (const char *) &name_tmp[name_len];
630   {
631     struct GNUNET_NAMESTORE_RecordData rd[rd_count];
632
633     if (GNUNET_OK != GNUNET_NAMESTORE_records_deserialize (rd_len, 
634                                                            rd_ser_tmp, 
635                                                            rd_count, 
636                                                            rd))
637     {
638       GNUNET_break (0);
639       return GNUNET_SYSERR;
640     }
641     if (NULL != ze->proc)
642       ze->proc (ze->proc_cls, 
643                 &msg->private_key, 
644                 name_tmp, 
645                 rd_count, rd);
646     return GNUNET_YES;
647   }
648 }
649
650
651 /**
652  * Handle incoming messages for zone iterations
653  *
654  * @param ze the respective zone iteration handle
655  * @param msg the message we received
656  * @param type the message type in HBO
657  * @param size the message size
658  * @return #GNUNET_YES on success, @a ze should be kept, #GNUNET_NO on success if @a ze should
659  *         not be kept any longer, #GNUNET_SYSERR on error (disconnect) and @a ze should be kept
660  */
661 static int
662 manage_zone_operations (struct GNUNET_NAMESTORE_ZoneIterator *ze,
663                         const struct GNUNET_MessageHeader *msg,
664                         int type, size_t size)
665 {
666   /* handle different message type */
667   switch (type) 
668   {
669   case GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT:
670     if (size < sizeof (struct RecordResultMessage))
671     {
672       GNUNET_break (0);
673       return GNUNET_SYSERR;
674     }
675     return handle_zone_iteration_response (ze,
676                                            (const struct RecordResultMessage *) msg, 
677                                            size);
678   default:
679     GNUNET_break (0);
680     return GNUNET_SYSERR;
681   }
682 }
683
684
685 /**
686  * Type of a function to call when we receive a message
687  * from the service.
688  *
689  * @param cls the `struct GNUNET_NAMESTORE_SchedulingHandle`
690  * @param msg message received, NULL on timeout or fatal error
691  */
692 static void
693 process_namestore_message (void *cls, 
694                            const struct GNUNET_MessageHeader *msg)
695 {
696   struct GNUNET_NAMESTORE_Handle *h = cls;
697   const struct GNUNET_NAMESTORE_Header *gm;
698   struct GNUNET_NAMESTORE_QueueEntry *qe;
699   struct GNUNET_NAMESTORE_ZoneIterator *ze;
700   uint16_t size;
701   uint16_t type;
702   uint32_t r_id;
703   int ret;
704
705   if (NULL == msg)
706   {
707     force_reconnect (h);
708     return;
709   }
710   size = ntohs (msg->size);
711   type = ntohs (msg->type);
712   if (size < sizeof (struct GNUNET_NAMESTORE_Header))
713   {
714     GNUNET_break_op (0);
715     GNUNET_CLIENT_receive (h->client, 
716                            &process_namestore_message, h,
717                            GNUNET_TIME_UNIT_FOREVER_REL);
718     return;
719   }
720   gm = (const struct GNUNET_NAMESTORE_Header *) msg;
721   r_id = ntohl (gm->r_id);
722
723   LOG (GNUNET_ERROR_TYPE_DEBUG,
724        "Received message type %u size %u op %u\n", 
725        (unsigned int) type,
726        (unsigned int) size, 
727        (unsigned int) r_id);
728
729   /* Is it a record related operation ? */
730   for (qe = h->op_head; qe != NULL; qe = qe->next)
731     if (qe->op_id == r_id)
732       break;
733   if (NULL != qe)
734   {
735     ret = manage_record_operations (qe, msg, type, size);
736     if (GNUNET_SYSERR == ret)    
737     {
738       /* protocol error, need to reconnect */
739       h->reconnect = GNUNET_YES;
740     }
741     else
742     {
743       /* client was notified about success or failure, clean up 'qe' */
744       GNUNET_CONTAINER_DLL_remove (h->op_head,
745                                    h->op_tail,
746                                    qe);
747       GNUNET_free (qe);
748     }
749   }
750   /* Is it a zone iteration operation? */
751   for (ze = h->z_head; ze != NULL; ze = ze->next)
752     if (ze->op_id == r_id)
753       break;
754   if (NULL != ze)
755   {
756     ret = manage_zone_operations (ze, msg, type, size);
757     if (GNUNET_NO == ret)
758     {
759       /* end of iteration, clean up 'ze' */
760       GNUNET_CONTAINER_DLL_remove (h->z_head,
761                                    h->z_tail,
762                                    ze);
763       GNUNET_free (ze);
764     }
765     if (GNUNET_SYSERR == ret)
766     {
767       /* protocol error, need to reconnect */
768       h->reconnect = GNUNET_YES;
769     }
770   }
771   if (GNUNET_YES == h->reconnect)
772   {
773     force_reconnect (h);
774     return;
775   }
776   GNUNET_CLIENT_receive (h->client, &process_namestore_message, h,
777                          GNUNET_TIME_UNIT_FOREVER_REL);
778 }
779
780
781 /**
782  * Transmit messages from the message queue to the service
783  * (if there are any, and if we are not already trying).
784  *
785  * @param h handle to use
786  */
787 static void
788 do_transmit (struct GNUNET_NAMESTORE_Handle *h);
789
790
791 /**
792  * We can now transmit a message to NAMESTORE. Do it.
793  *
794  * @param cls the `struct GNUNET_NAMESTORE_Handle`
795  * @param size number of bytes we can transmit
796  * @param buf where to copy the messages
797  * @return number of bytes copied into @a buf
798  */
799 static size_t
800 transmit_message_to_namestore (void *cls, 
801                                size_t size, 
802                                void *buf)
803 {
804   struct GNUNET_NAMESTORE_Handle *h = cls;
805   struct PendingMessage *p;
806   size_t ret;
807   char *cbuf;
808
809   h->th = NULL;
810   if ((0 == size) || (NULL == buf))
811   {
812     force_reconnect (h);
813     return 0;
814   }
815   ret = 0;
816   cbuf = buf;
817   while ( (NULL != (p = h->pending_head)) && 
818           (p->size <= size) )
819   {
820     memcpy (&cbuf[ret], &p[1], p->size);
821     ret += p->size;
822     size -= p->size;
823     GNUNET_CONTAINER_DLL_remove (h->pending_head,
824                                  h->pending_tail, 
825                                  p);
826     if (GNUNET_NO == h->is_receiving)
827     {
828       h->is_receiving = GNUNET_YES;
829       GNUNET_CLIENT_receive (h->client,
830                              &process_namestore_message, h,
831                              GNUNET_TIME_UNIT_FOREVER_REL);
832     }
833     GNUNET_free (p);
834   }
835   do_transmit (h);
836   return ret;
837 }
838
839
840 /**
841  * Transmit messages from the message queue to the service
842  * (if there are any, and if we are not already trying).
843  *
844  * @param h handle to use
845  */
846 static void
847 do_transmit (struct GNUNET_NAMESTORE_Handle *h)
848 {
849   struct PendingMessage *p;
850
851   if (NULL != h->th)
852     return; /* transmission request already pending */
853   if (NULL == (p = h->pending_head))
854     return; /* transmission queue empty */
855   if (NULL == h->client)
856     return;                     /* currently reconnecting */
857   h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, p->size,
858                                                GNUNET_TIME_UNIT_FOREVER_REL,
859                                                GNUNET_NO, &transmit_message_to_namestore,
860                                                h);
861 }
862
863
864 /**
865  * Reconnect to namestore service.
866  *
867  * @param h the handle to the NAMESTORE service
868  */
869 static void
870 reconnect (struct GNUNET_NAMESTORE_Handle *h)
871 {
872   GNUNET_assert (NULL == h->client);
873   h->client = GNUNET_CLIENT_connect ("namestore", h->cfg);
874   GNUNET_assert (NULL != h->client);
875   do_transmit (h);
876 }
877
878
879 /**
880  * Re-establish the connection to the service.
881  *
882  * @param cls handle to use to re-connect.
883  * @param tc scheduler context
884  */
885 static void
886 reconnect_task (void *cls, 
887                 const struct GNUNET_SCHEDULER_TaskContext *tc)
888 {
889   struct GNUNET_NAMESTORE_Handle *h = cls;
890
891   h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
892   reconnect (h);
893 }
894
895
896 /**
897  * Disconnect from service and then reconnect.
898  *
899  * @param h our handle
900  */
901 static void
902 force_reconnect (struct GNUNET_NAMESTORE_Handle *h)
903 {
904   h->reconnect = GNUNET_NO;
905   GNUNET_CLIENT_disconnect (h->client);
906   h->is_receiving = GNUNET_NO;
907   h->client = NULL;
908   h->reconnect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
909                                                     &reconnect_task,
910                                                     h);
911 }
912
913
914 /**
915  * Get a fresh operation id to distinguish between namestore requests
916  *
917  * @param h the namestore handle
918  * @return next operation id to use
919  */
920 static uint32_t
921 get_op_id (struct GNUNET_NAMESTORE_Handle *h)
922 {
923   return h->last_op_id_used++;
924 }
925
926
927 /**
928  * Initialize the connection with the NAMESTORE service.
929  *
930  * @param cfg configuration to use
931  * @return handle to the GNS service, or NULL on error
932  */
933 struct GNUNET_NAMESTORE_Handle *
934 GNUNET_NAMESTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
935 {
936   struct GNUNET_NAMESTORE_Handle *h;
937
938   h = GNUNET_new (struct GNUNET_NAMESTORE_Handle);
939   h->cfg = cfg;
940   h->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect_task, h);
941   h->last_op_id_used = 0;
942   return h;
943 }
944
945
946 /**
947  * Disconnect from the namestore service (and free associated
948  * resources).
949  *
950  * @param h handle to the namestore
951  */
952 void
953 GNUNET_NAMESTORE_disconnect (struct GNUNET_NAMESTORE_Handle *h)
954 {
955   struct PendingMessage *p;
956   struct GNUNET_NAMESTORE_QueueEntry *q;
957   struct GNUNET_NAMESTORE_ZoneIterator *z;
958
959   LOG (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
960   GNUNET_assert (NULL != h);
961   while (NULL != (p = h->pending_head))
962   {
963     GNUNET_CONTAINER_DLL_remove (h->pending_head, h->pending_tail, p);
964     GNUNET_free (p);
965   }
966   GNUNET_break (NULL == h->op_head);
967   while (NULL != (q = h->op_head))
968   {
969     GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, q);
970     GNUNET_free (q);
971   }
972   GNUNET_break (NULL == h->z_head);
973   while (NULL != (z = h->z_head))
974   {
975     GNUNET_CONTAINER_DLL_remove (h->z_head, h->z_tail, z);
976     GNUNET_free (z);
977   }
978   if (NULL != h->client)
979   {
980     GNUNET_CLIENT_disconnect (h->client);
981     h->client = NULL;
982   }
983   if (GNUNET_SCHEDULER_NO_TASK != h->reconnect_task)
984   {
985     GNUNET_SCHEDULER_cancel (h->reconnect_task);
986     h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
987   }
988   GNUNET_free (h);
989 }
990
991
992 /**
993  * Store an item in the namestore.  If the item is already present,
994  * it is replaced with the new record.  
995  *
996  * @param h handle to the namestore
997  * @param block block to store
998  * @param cont continuation to call when done
999  * @param cont_cls closure for cont
1000  * @return handle to abort the request
1001  */
1002 struct GNUNET_NAMESTORE_QueueEntry *
1003 GNUNET_NAMESTORE_block_cache (struct GNUNET_NAMESTORE_Handle *h,
1004                               const struct GNUNET_NAMESTORE_Block *block,
1005                               GNUNET_NAMESTORE_ContinuationWithStatus cont,
1006                               void *cont_cls)
1007 {
1008   struct GNUNET_NAMESTORE_QueueEntry *qe;
1009   struct PendingMessage *pe;
1010   struct BlockCacheMessage *msg;
1011   uint32_t rid;
1012   size_t blen;
1013   size_t msg_size;
1014
1015   GNUNET_assert (NULL != h);
1016   blen = ntohl (block->purpose.size) 
1017     - sizeof (struct GNUNET_TIME_AbsoluteNBO) 
1018     - sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose);
1019   rid = get_op_id (h);
1020   qe = GNUNET_new (struct GNUNET_NAMESTORE_QueueEntry);
1021   qe->nsh = h;
1022   qe->cont = cont;
1023   qe->cont_cls = cont_cls;
1024   qe->op_id = rid;
1025   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, qe);
1026
1027   /* setup msg */
1028   msg_size = sizeof (struct BlockCacheMessage) + blen;
1029   pe = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size);
1030   pe->size = msg_size;
1031   msg = (struct BlockCacheMessage *) &pe[1];
1032   msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_BLOCK_CACHE);
1033   msg->gns_header.header.size = htons (msg_size);
1034   msg->gns_header.r_id = htonl (rid);
1035   msg->expire = block->expiration_time;
1036   msg->signature = block->signature;
1037   msg->derived_key = block->derived_key;
1038   memcpy (&msg[1], &block[1], blen);
1039   LOG (GNUNET_ERROR_TYPE_DEBUG, 
1040        "Sending `%s' message with size %u\n", 
1041        "NAMESTORE_BLOCK_CACHE", 
1042        (unsigned int) msg_size);
1043   GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe);
1044   do_transmit(h);
1045   return qe;
1046 }
1047
1048
1049 /**
1050  * Store an item in the namestore.  If the item is already present,
1051  * it is replaced with the new record.  Use an empty array to
1052  * remove all records under the given name.
1053  *
1054  * @param h handle to the namestore
1055  * @param pkey private key of the zone
1056  * @param label name that is being mapped (at most 255 characters long)
1057  * @param rd_count number of records in the 'rd' array
1058  * @param rd array of records with data to store
1059  * @param cont continuation to call when done
1060  * @param cont_cls closure for 'cont'
1061  * @return handle to abort the request
1062  */
1063 struct GNUNET_NAMESTORE_QueueEntry *
1064 GNUNET_NAMESTORE_records_store (struct GNUNET_NAMESTORE_Handle *h,
1065                                 const struct GNUNET_CRYPTO_EccPrivateKey *pkey,
1066                                 const char *label,
1067                                 unsigned int rd_count,
1068                                 const struct GNUNET_NAMESTORE_RecordData *rd,
1069                                 GNUNET_NAMESTORE_ContinuationWithStatus cont,
1070                                 void *cont_cls)
1071 {
1072   struct GNUNET_NAMESTORE_QueueEntry *qe;
1073   struct PendingMessage *pe;
1074   char *name_tmp;
1075   char *rd_ser;
1076   size_t rd_ser_len;
1077   size_t msg_size;
1078   size_t name_len;
1079   uint32_t rid;
1080   struct RecordStoreMessage *msg;
1081
1082   GNUNET_assert (NULL != h);
1083   GNUNET_assert (NULL != pkey);
1084   GNUNET_assert (NULL != label);
1085   name_len = strlen (label) + 1;
1086   if (name_len > MAX_NAME_LEN)
1087   {
1088     GNUNET_break (0);
1089     return NULL;
1090   }
1091   rid = get_op_id (h);
1092   qe = GNUNET_new (struct GNUNET_NAMESTORE_QueueEntry);
1093   qe->nsh = h;
1094   qe->cont = cont;
1095   qe->cont_cls = cont_cls;
1096   qe->op_id = rid;
1097   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, qe);
1098
1099   /* setup msg */
1100   rd_ser_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
1101   msg_size = sizeof (struct RecordStoreMessage) + name_len + rd_ser_len;
1102   pe = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size);
1103   pe->size = msg_size;
1104   msg = (struct RecordStoreMessage *) &pe[1];
1105   msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE);
1106   msg->gns_header.header.size = htons (msg_size);
1107   msg->gns_header.r_id = htonl (rid);
1108   msg->name_len = htons (name_len);
1109   msg->rd_count = htons (rd_count);
1110   msg->rd_len = htons (rd_ser_len);
1111   msg->reserved = htons (0);
1112   msg->private_key = *pkey;
1113
1114   name_tmp = (char *) &msg[1];
1115   memcpy (name_tmp, label, name_len);
1116   rd_ser = &name_tmp[name_len];
1117   GNUNET_break (rd_ser_len == 
1118                 GNUNET_NAMESTORE_records_serialize (rd_count, rd, 
1119                                                     rd_ser_len, 
1120                                                     rd_ser));
1121   LOG (GNUNET_ERROR_TYPE_DEBUG, 
1122        "Sending `%s' message for name `%s' with size %u and %u records\n", 
1123        "NAMESTORE_RECORD_STORE", label, msg_size,
1124        rd_count);
1125   GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe);
1126   do_transmit(h);
1127   return qe;
1128 }
1129
1130
1131 /**
1132  * Get a result for a particular key from the namestore.  The processor
1133  * will only be called once.  
1134  *
1135  * @param h handle to the namestore
1136  * @param derived_hash hash of zone key combined with name to lookup
1137  * @param proc function to call on the matching block, or with
1138  *        NULL if there is no matching block
1139  * @param proc_cls closure for proc
1140  * @return a handle that can be used to cancel
1141  */
1142 struct GNUNET_NAMESTORE_QueueEntry *
1143 GNUNET_NAMESTORE_lookup_block (struct GNUNET_NAMESTORE_Handle *h, 
1144                                const struct GNUNET_HashCode *derived_hash,
1145                                GNUNET_NAMESTORE_BlockProcessor proc, void *proc_cls)
1146 {
1147   struct GNUNET_NAMESTORE_QueueEntry *qe;
1148   struct PendingMessage *pe;
1149   struct LookupBlockMessage *msg;
1150   size_t msg_size;
1151   uint32_t rid;
1152
1153   GNUNET_assert (NULL != h);
1154   GNUNET_assert (NULL != derived_hash);
1155   LOG (GNUNET_ERROR_TYPE_DEBUG,
1156        "Looking for block under %s\n",
1157        GNUNET_h2s (derived_hash));
1158   rid = get_op_id(h);
1159   qe = GNUNET_new (struct GNUNET_NAMESTORE_QueueEntry);
1160   qe->nsh = h;
1161   qe->block_proc = proc;
1162   qe->block_proc_cls = proc_cls;
1163   qe->op_id = rid;
1164   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, qe);
1165
1166   msg_size = sizeof (struct LookupBlockMessage);
1167   pe = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size);
1168   pe->size = msg_size;
1169   msg = (struct LookupBlockMessage *) &pe[1];
1170   msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_BLOCK);
1171   msg->gns_header.header.size = htons (msg_size);
1172   msg->gns_header.r_id = htonl (rid);
1173   msg->query = *derived_hash;
1174   GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe);
1175   do_transmit(h);
1176   return qe;
1177 }
1178
1179
1180 /**
1181  * Look for an existing PKEY delegation record for a given public key.
1182  * Returns at most one result to the processor.
1183  *
1184  * @param h handle to the namestore
1185  * @param zone public key of the zone to look up in, never NULL
1186  * @param value_zone public key of the target zone (value), never NULL
1187  * @param proc function to call on the matching records, or with
1188  *        NULL (rd_count == 0) if there are no matching records
1189  * @param proc_cls closure for @a proc
1190  * @return a handle that can be used to
1191  *         cancel
1192  */
1193 struct GNUNET_NAMESTORE_QueueEntry *
1194 GNUNET_NAMESTORE_zone_to_name (struct GNUNET_NAMESTORE_Handle *h,
1195                                const struct GNUNET_CRYPTO_EccPrivateKey *zone,
1196                                const struct GNUNET_CRYPTO_EccPublicSignKey *value_zone,
1197                                GNUNET_NAMESTORE_RecordMonitor proc, void *proc_cls)
1198 {
1199   struct GNUNET_NAMESTORE_QueueEntry *qe;
1200   struct PendingMessage *pe;
1201   struct ZoneToNameMessage * msg;
1202   size_t msg_size;
1203   uint32_t rid;
1204
1205   GNUNET_assert (NULL != h);
1206   GNUNET_assert (NULL != zone);
1207   GNUNET_assert (NULL != value_zone);
1208   rid = get_op_id(h);
1209   qe = GNUNET_new (struct GNUNET_NAMESTORE_QueueEntry);
1210   qe->nsh = h;
1211   qe->proc = proc;
1212   qe->proc_cls = proc_cls;
1213   qe->op_id = rid;
1214   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, qe);
1215
1216   msg_size = sizeof (struct ZoneToNameMessage);
1217   pe = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size);
1218   pe->size = msg_size;
1219   msg = (struct ZoneToNameMessage *) &pe[1];
1220   msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME);
1221   msg->gns_header.header.size = htons (msg_size);
1222   msg->gns_header.r_id = htonl (rid);
1223   msg->zone = *zone;
1224   msg->value_zone = *value_zone;
1225
1226   /* transmit message */
1227   GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe);
1228   do_transmit(h);
1229   return qe;
1230 }
1231
1232
1233 /**
1234  * Starts a new zone iteration (used to periodically PUT all of our
1235  * records into our DHT). This MUST lock the struct GNUNET_NAMESTORE_Handle
1236  * for any other calls than #GNUNET_NAMESTORE_zone_iterator_next and
1237  * #GNUNET_NAMESTORE_zone_iteration_stop. @a proc will be called once
1238  * immediately, and then again after
1239  * #GNUNET_NAMESTORE_zone_iterator_next is invoked.
1240  *
1241  * @param h handle to the namestore
1242  * @param zone zone to access, NULL for all zones
1243  * @param proc function to call on each name from the zone; it
1244  *        will be called repeatedly with a value (if available)
1245  *        and always once at the end with a name of NULL.
1246  * @param proc_cls closure for @a proc
1247  * @return an iterator handle to use for iteration
1248  */
1249 struct GNUNET_NAMESTORE_ZoneIterator *
1250 GNUNET_NAMESTORE_zone_iteration_start (struct GNUNET_NAMESTORE_Handle *h,
1251                                        const struct GNUNET_CRYPTO_EccPrivateKey *zone,
1252                                        GNUNET_NAMESTORE_RecordMonitor proc,
1253                                        void *proc_cls)
1254 {
1255   struct GNUNET_NAMESTORE_ZoneIterator *it;
1256   struct PendingMessage *pe;
1257   struct ZoneIterationStartMessage * msg;
1258   size_t msg_size;
1259   uint32_t rid;
1260
1261   GNUNET_assert (NULL != h);
1262   rid = get_op_id(h);
1263   it = GNUNET_new (struct GNUNET_NAMESTORE_ZoneIterator);
1264   it->h = h;
1265   it->proc = proc;
1266   it->proc_cls = proc_cls;
1267   it->op_id = rid;
1268   if (NULL != zone)
1269     it->zone = *zone;
1270   GNUNET_CONTAINER_DLL_insert_tail (h->z_head, h->z_tail, it);
1271
1272   msg_size = sizeof (struct ZoneIterationStartMessage);
1273   pe = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size);
1274   pe->size = msg_size;
1275   msg = (struct ZoneIterationStartMessage *) &pe[1];
1276   msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START);
1277   msg->gns_header.header.size = htons (msg_size);
1278   msg->gns_header.r_id = htonl (rid);
1279   if (NULL != zone)
1280     msg->zone = *zone;
1281   GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe);
1282   do_transmit(h);
1283   return it;
1284 }
1285
1286
1287 /**
1288  * Calls the record processor specified in #GNUNET_NAMESTORE_zone_iteration_start
1289  * for the next record.
1290  *
1291  * @param it the iterator
1292  */
1293 void
1294 GNUNET_NAMESTORE_zone_iterator_next (struct GNUNET_NAMESTORE_ZoneIterator *it)
1295 {
1296   struct GNUNET_NAMESTORE_Handle *h;
1297   struct ZoneIterationNextMessage * msg;
1298   struct PendingMessage *pe;
1299   size_t msg_size;
1300
1301   GNUNET_assert (NULL != it);
1302   h = it->h;
1303   msg_size = sizeof (struct ZoneIterationNextMessage);
1304   pe = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size);
1305   pe->size = msg_size;
1306   msg = (struct ZoneIterationNextMessage *) &pe[1];
1307   msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT);
1308   msg->gns_header.header.size = htons (msg_size);
1309   msg->gns_header.r_id = htonl (it->op_id);
1310   LOG (GNUNET_ERROR_TYPE_DEBUG,
1311        "Sending `%s' message\n", 
1312        "ZONE_ITERATION_NEXT");
1313   GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe);
1314   do_transmit(h);
1315 }
1316
1317
1318 /**
1319  * Stops iteration and releases the namestore handle for further calls.
1320  *
1321  * @param it the iterator
1322  */
1323 void
1324 GNUNET_NAMESTORE_zone_iteration_stop (struct GNUNET_NAMESTORE_ZoneIterator *it)
1325 {
1326   struct GNUNET_NAMESTORE_Handle *h;
1327   struct PendingMessage *pe;
1328   size_t msg_size;
1329   struct ZoneIterationStopMessage * msg;
1330
1331   GNUNET_assert (NULL != it);
1332   h = it->h;
1333   GNUNET_CONTAINER_DLL_remove (h->z_head,
1334                                h->z_tail,
1335                                it);
1336   msg_size = sizeof (struct ZoneIterationStopMessage);
1337   pe = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size);
1338   pe->size = msg_size;
1339   msg = (struct ZoneIterationStopMessage *) &pe[1];
1340   msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP);
1341   msg->gns_header.header.size = htons (msg_size);
1342   msg->gns_header.r_id = htonl (it->op_id);
1343   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1344               "Sending `%s' message\n", 
1345               "ZONE_ITERATION_STOP");
1346   GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe);
1347   do_transmit(h);
1348   GNUNET_free (it);
1349 }
1350
1351
1352 /**
1353  * Cancel a namestore operation.  The final callback from the
1354  * operation must not have been done yet.
1355  *
1356  * @param qe operation to cancel
1357  */
1358 void
1359 GNUNET_NAMESTORE_cancel (struct GNUNET_NAMESTORE_QueueEntry *qe)
1360 {
1361   struct GNUNET_NAMESTORE_Handle *h = qe->nsh;
1362
1363   GNUNET_assert (NULL != qe);
1364   GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, qe);
1365   GNUNET_free(qe);
1366 }
1367
1368
1369 /* end of namestore_api.c */