-ideas for stuff
[oweals/gnunet.git] / src / lockmanager / lockmanager_api.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012 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 2, 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 lockmanager/lockmanager_api.c
23  * @brief API implementation of gnunet_lockmanager_service.h
24  * @author Sree Harsha Totakura
25  */
26
27 /**
28  * To be fixed:
29  *  Should the handle be freed when the connection to service is lost?
30  *  Should cancel_request have a call back (else simultaneous calls break)
31  */
32
33 #include "platform.h"
34 #include "gnunet_common.h"
35 #include "gnunet_container_lib.h"
36 #include "gnunet_client_lib.h"
37 #include "gnunet_crypto_lib.h"
38 #include "gnunet_lockmanager_service.h"
39 #include "gnunet_protocols.h"
40
41 #include "lockmanager.h"
42
43 #define LOG(kind,...) \
44   GNUNET_log_from (kind, "lockmanager-api",__VA_ARGS__)
45
46 #define TIME_REL_MINS(min) \
47   GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, min)
48
49 #define TIMEOUT TIME_REL_MINS(3)
50
51
52 /**
53  * The message queue
54  */
55 struct MessageQueue
56 {
57   /**
58    * The next pointer for doubly linked list
59    */
60   struct MessageQueue *next;
61
62   /**
63    * The prev pointer for doubly linked list
64    */
65   struct MessageQueue *prev;
66   
67   /**
68    * The LOCKMANAGER Message
69    */
70   struct GNUNET_LOCKMANAGER_Message *msg;
71
72   /**
73    * If this is a AQUIRE_LOCK message, this is the
74    * affiliated locking request.
75    */
76   struct GNUNET_LOCKMANAGER_LockingRequest *lr;
77 };
78
79
80 /**
81  * Handler for the lockmanager service
82  */
83 struct GNUNET_LOCKMANAGER_Handle
84 {
85   /**
86    * The client connection to the service
87    */
88   struct GNUNET_CLIENT_Connection *conn;
89
90   /**
91    * The transmit handle for transmissions using conn
92    */
93   struct GNUNET_CLIENT_TransmitHandle *transmit_handle;
94
95   /**
96    * Hashmap handle
97    */
98   struct GNUNET_CONTAINER_MultiHashMap *hashmap;
99
100   /**
101    * Double linked list head for message queue
102    */
103   struct MessageQueue *mq_head;
104
105   /**
106    * Double linked list tail for message queue
107    */
108   struct MessageQueue *mq_tail;
109
110   /**
111    * Are we currently handling replies?
112    */
113   int in_replies;
114 };
115
116
117 /**
118  * Structure for Locking Request
119  */
120 struct GNUNET_LOCKMANAGER_LockingRequest
121 {
122   /**
123    * The handle associated with this request
124    */
125   struct GNUNET_LOCKMANAGER_Handle *handle;
126
127   /**
128    * The status callback
129    */
130   GNUNET_LOCKMANAGER_StatusCallback status_cb;
131
132   /**
133    * Entry in the request message queue for aquiring this
134    * lock; NULL after request has been sent.
135    */
136   struct MessageQueue *mqe;
137
138   /**
139    * Closure for the status callback
140    */
141   void *status_cb_cls;
142
143   /**
144    * The locking domain of this request
145    */
146   char *domain;
147   
148   /**
149    * The lock
150    */
151   uint32_t lock;
152
153   /**
154    * The status of the lock
155    */
156   enum GNUNET_LOCKMANAGER_Status status;
157 };
158
159
160 /**
161  * Structure for matching a lock
162  */
163 struct LockingRequestMatch
164 {
165   /**
166    * The matched LockingRequest entry; Should be NULL if no entry is found
167    */
168   struct GNUNET_LOCKMANAGER_LockingRequest *matched_entry;
169
170   /**
171    * The locking domain name of the lock
172    */
173   const char *domain;
174
175   /**
176    * The lock number
177    */
178   uint32_t lock;
179 };
180
181
182 /**
183  * Handler for server replies
184  *
185  * @param cls the LOCKMANAGER_Handle
186  * @param msg received message, NULL on timeout or fatal error
187  */
188 static void 
189 handle_replies (void *cls,
190                 const struct GNUNET_MessageHeader *msg);
191
192
193 /**
194  * Transmit notify for sending message to server
195  *
196  * @param cls the lockmanager handle
197  * @param size number of bytes available in buf
198  * @param buf where the callee should write the message
199  * @return number of bytes written to buf
200  */
201 static size_t 
202 transmit_notify (void *cls, size_t size, void *buf)
203 {
204   struct GNUNET_LOCKMANAGER_Handle *handle = cls;
205   struct MessageQueue *queue_entity;
206   uint16_t msg_size;
207
208   handle->transmit_handle = NULL;
209   queue_entity = handle->mq_head;
210   GNUNET_assert (NULL != queue_entity);
211   if ((0 == size) || (NULL == buf))
212   {
213     handle->transmit_handle =
214       GNUNET_CLIENT_notify_transmit_ready (handle->conn,
215                                            ntohs
216                                            (queue_entity->msg->header.size),
217                                            GNUNET_TIME_UNIT_FOREVER_REL,
218                                            GNUNET_YES,
219                                            &transmit_notify,
220                                            handle);
221     return 0;
222   } 
223   msg_size = ntohs (queue_entity->msg->header.size);
224   GNUNET_assert (size >= msg_size);
225   memcpy (buf, queue_entity->msg, msg_size);
226   LOG (GNUNET_ERROR_TYPE_DEBUG,
227        "Message of size %u sent\n", msg_size);
228   GNUNET_free (queue_entity->msg);
229   GNUNET_CONTAINER_DLL_remove (handle->mq_head,
230                                handle->mq_tail,
231                                queue_entity);
232   GNUNET_free (queue_entity);
233   queue_entity = handle->mq_head;
234   if (NULL != queue_entity)
235   {
236     handle->transmit_handle =
237       GNUNET_CLIENT_notify_transmit_ready (handle->conn,
238                                            ntohs
239                                            (queue_entity->msg->header.size),
240                                            TIMEOUT,
241                                            GNUNET_YES,
242                                            &transmit_notify,
243                                            handle);
244   }
245   if (GNUNET_NO == handle->in_replies)
246   {
247     GNUNET_CLIENT_receive (handle->conn,
248                            &handle_replies,
249                            handle,
250                            GNUNET_TIME_UNIT_FOREVER_REL);
251     handle->in_replies = GNUNET_YES;
252   }
253   return msg_size;
254 }
255
256
257 /**
258  * Queues a message into handle's send message queue
259  *
260  * @param handle the lockmanager handle whose queue will be used
261  * @param msg the message to be queued
262  */
263 static void
264 queue_message (struct GNUNET_LOCKMANAGER_Handle *handle,
265                struct GNUNET_LOCKMANAGER_Message *msg)
266 {
267   struct MessageQueue *queue_entity;
268
269   GNUNET_assert (NULL != msg);
270   queue_entity = GNUNET_malloc (sizeof (struct MessageQueue));
271   queue_entity->msg = msg;
272   GNUNET_CONTAINER_DLL_insert_tail (handle->mq_head,
273                                     handle->mq_tail,
274                                     queue_entity);
275   if (NULL == handle->transmit_handle)
276   {
277     handle->transmit_handle =
278       GNUNET_CLIENT_notify_transmit_ready (handle->conn,
279                                            ntohs (msg->header.size),
280                                            TIMEOUT,
281                                            GNUNET_YES,
282                                            &transmit_notify,
283                                            handle);
284   }
285 }
286
287
288 /**
289  * Get the key for the given lock in the 'lock_map'.
290  *
291  * @param domain_name
292  * @param lock_number
293  * @param key set to the key
294  */
295 static void
296 get_key (const char *domain_name,
297          uint32_t lock_number,
298          struct GNUNET_HashCode *key)
299 {
300   uint32_t *last_32;
301
302   GNUNET_CRYPTO_hash (domain_name,
303                       strlen (domain_name),
304                       key);
305   last_32 = (uint32_t *) key;
306   *last_32 ^= lock_number;
307 }
308
309
310 /**
311  * Hashmap iterator for matching a LockingRequest
312  *
313  * @param cls the LockingRequestMatch structure
314  * @param key current key code
315  * @param value value in the hash map (struct GNUNET_LOCKMANAGER_LockingRequest)
316  * @return GNUNET_YES if we should continue to
317  *         iterate,
318  *         GNUNET_NO if not. 
319  */
320 static int
321 match_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
322 {
323   struct LockingRequestMatch *match = cls;
324   struct GNUNET_LOCKMANAGER_LockingRequest *lr = value;
325
326   if ( (match->lock == lr->lock) && (0 == strcmp (match->domain, lr->domain)) )
327   {
328     match->matched_entry = lr;    
329     return GNUNET_NO;
330   }
331   return GNUNET_YES;
332 }
333
334
335 /**
336  * Function to find a LockingRequest associated with the given domain and lock
337  * attributes in the map
338  *
339  * @param map the map where the LockingRequests are stored
340  * @param domain the locking domain name
341  * @param lock the lock number
342  * @return the found LockingRequest; NULL if a matching LockingRequest wasn't
343  *           found 
344  */
345 static struct GNUNET_LOCKMANAGER_LockingRequest *
346 hashmap_find_lockingrequest (const struct GNUNET_CONTAINER_MultiHashMap *map,
347                              const char *domain,
348                              uint32_t lock)
349 {
350   struct GNUNET_HashCode hash;
351   struct LockingRequestMatch lock_match;
352
353   lock_match.matched_entry = NULL;
354   lock_match.domain = domain;
355   lock_match.lock = lock;
356   get_key (domain, lock, &hash);
357   GNUNET_CONTAINER_multihashmap_get_multiple (map,
358                                               &hash,
359                                               &match_iterator,
360                                               &lock_match);
361   return lock_match.matched_entry;
362 }
363
364
365 /**
366  * Task for calling status change callback for a lock
367  *
368  * @param cls the LockingRequest associated with this lock
369  * @param tc the TaskScheduler context
370  */
371 static void
372 call_status_cb_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
373 {
374   const struct GNUNET_LOCKMANAGER_LockingRequest *r = cls;
375
376   if (NULL != r->status_cb)
377   {
378     LOG (GNUNET_ERROR_TYPE_DEBUG,
379          "Calling status change for SUCCESS on lock num: %d, domain: %s\n",
380          r->lock, r->domain);
381     r->status_cb (r->status_cb_cls,
382                   r->domain,
383                   r->lock,
384                   r->status);
385   }
386 }
387
388
389 /**
390  * Function to generate acquire message for a lock
391  *
392  * @param domain_name the domain name of the lock
393  * @param lock the lock number
394  * @return the generated GNUNET_LOCKMANAGER_Message
395  */
396 static struct GNUNET_LOCKMANAGER_Message *
397 generate_acquire_msg (const char *domain_name, uint32_t lock)
398 {
399   struct GNUNET_LOCKMANAGER_Message *msg;
400   size_t domain_name_len;
401   uint16_t  msg_size;
402   
403   domain_name_len = strlen (domain_name) + 1;
404   msg_size = sizeof (struct GNUNET_LOCKMANAGER_Message) + domain_name_len;
405   msg = GNUNET_malloc (msg_size);
406   msg->header.type = htons (GNUNET_MESSAGE_TYPE_LOCKMANAGER_ACQUIRE);
407   msg->header.size = htons (msg_size);
408   msg->lock = htonl (lock);
409   memcpy (&msg[1], domain_name, domain_name_len);
410   return msg;
411 }
412
413
414 /**
415  * Iterator to call relase on locks
416  *
417  * @param cls the lockmanager handle
418  * @param key current key code
419  * @param value the Locking request
420  * @return GNUNET_YES if we should continue to
421  *         iterate,
422  *         GNUNET_NO if not.
423  */
424 static int
425 release_n_retry_iterator (void *cls,
426                           const struct GNUNET_HashCode * key,
427                           void *value)
428 {
429   struct GNUNET_LOCKMANAGER_LockingRequest *r = value;
430   struct GNUNET_LOCKMANAGER_Handle *h = cls;
431   struct GNUNET_LOCKMANAGER_Message *msg;
432
433   msg = generate_acquire_msg (r->domain, r->lock);
434   queue_message (h, msg);
435   if (GNUNET_LOCKMANAGER_RELEASE == r->status)
436     return GNUNET_YES;
437   if (NULL != r->status_cb)
438   {
439     LOG (GNUNET_ERROR_TYPE_DEBUG,
440          "Calling status change for RELEASE on lock num: %d, domain: %s\n",
441          r->lock, r->domain);
442     r->status = GNUNET_LOCKMANAGER_RELEASE;
443     r->status_cb (r->status_cb_cls,
444                   r->domain,
445                   r->lock,
446                   GNUNET_LOCKMANAGER_RELEASE);
447   }
448   return GNUNET_YES;
449 }
450
451
452 /**
453  * Handler for server replies
454  *
455  * @param cls the LOCKMANAGER_Handle
456  * @param msg received message, NULL on timeout or fatal error
457  */
458 static void 
459 handle_replies (void *cls,
460                 const struct GNUNET_MessageHeader *msg)
461 {
462   struct GNUNET_LOCKMANAGER_Handle *handle = cls;
463   const struct GNUNET_LOCKMANAGER_Message *m;
464   struct GNUNET_LOCKMANAGER_LockingRequest *lr;
465   const char *domain;
466   struct GNUNET_HashCode hash;
467   uint32_t lock;
468   uint16_t msize;
469
470   handle->in_replies = GNUNET_NO;
471   if (NULL == msg)
472   {
473     LOG (GNUNET_ERROR_TYPE_DEBUG,
474          "Lockmanager service not available or went down\n");    
475     /* Should release all locks and retry to acquire them */
476     GNUNET_CONTAINER_multihashmap_iterate (handle->hashmap,
477                                            &release_n_retry_iterator,
478                                            handle);
479     return;
480   }
481   GNUNET_CLIENT_receive (handle->conn,
482                          &handle_replies,
483                          handle,
484                          GNUNET_TIME_UNIT_FOREVER_REL);
485   handle->in_replies = GNUNET_YES;
486   if (GNUNET_MESSAGE_TYPE_LOCKMANAGER_SUCCESS != ntohs(msg->type))
487   {
488     GNUNET_break (0);
489     return;
490   }
491   msize = ntohs (msg->size);
492   if (msize <= sizeof (struct GNUNET_LOCKMANAGER_Message))
493   {
494     GNUNET_break (0);
495     return;
496   }
497   m = (const struct GNUNET_LOCKMANAGER_Message *) msg;
498   domain = (const char *) &m[1];
499   msize -= sizeof (struct GNUNET_LOCKMANAGER_Message);
500   if ('\0' != domain[msize-1])
501   {
502     GNUNET_break (0);
503     return;
504   }
505
506   lock = ntohl (m->lock);
507   get_key (domain, lock, &hash);      
508   LOG (GNUNET_ERROR_TYPE_DEBUG,
509        "Received SUCCESS message for lock: %d, domain %s\n",
510        lock, domain);
511   if (NULL == (lr = hashmap_find_lockingrequest (handle->hashmap,
512                                                  domain,
513                                                  lock)))
514   {
515     GNUNET_break (0);
516     return;
517   }
518   if (GNUNET_LOCKMANAGER_SUCCESS == lr->status)
519   {
520     GNUNET_break (0);
521     return;
522   }
523   LOG (GNUNET_ERROR_TYPE_DEBUG,
524        "Changing status for lock: %d in domain: %s to SUCCESS\n",
525        lr->lock, lr->domain);
526   lr->status = GNUNET_LOCKMANAGER_SUCCESS;
527   GNUNET_SCHEDULER_add_continuation (&call_status_cb_task,
528                                      lr,
529                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
530 }
531
532
533 /**
534  * Iterator to free hash map entries.
535  *
536  * @param cls the lockmanger handle
537  * @param key current key code
538  * @param value the Locking request
539  * @return GNUNET_YES if we should continue to
540  *         iterate,
541  *         GNUNET_NO if not.
542  */
543 static int
544 free_iterator(void *cls,
545               const struct GNUNET_HashCode * key,
546               void *value)
547 {
548   struct GNUNET_LOCKMANAGER_Handle *h = cls;
549   struct GNUNET_LOCKMANAGER_LockingRequest *r = value;
550
551   LOG (GNUNET_ERROR_TYPE_DEBUG,
552        "Clearing locking request\n");
553   GNUNET_assert (GNUNET_YES == 
554                  GNUNET_CONTAINER_multihashmap_remove (h->hashmap,
555                                                        key,
556                                                        value));
557   GNUNET_free (r->domain);
558   GNUNET_free (r);
559   return GNUNET_YES;
560 }
561
562
563 /*******************/
564 /* API Definitions */
565 /*******************/
566
567
568 /**
569  * Connect to the lockmanager service
570  *
571  * @param cfg the configuration to use
572  *
573  * @return upon success the handle to the service; NULL upon error
574  */
575 struct GNUNET_LOCKMANAGER_Handle *
576 GNUNET_LOCKMANAGER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
577 {
578   struct GNUNET_LOCKMANAGER_Handle *h;
579
580   LOG (GNUNET_ERROR_TYPE_DEBUG, "%s()\n", __func__);
581   h = GNUNET_malloc (sizeof (struct GNUNET_LOCKMANAGER_Handle));
582   h->conn = GNUNET_CLIENT_connect ("lockmanager", cfg);
583   if (NULL == h->conn)
584   {
585     GNUNET_free (h);
586     LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__);
587     return NULL;
588   }  
589   h->hashmap = GNUNET_CONTAINER_multihashmap_create (15);
590   GNUNET_assert (NULL != h->hashmap);
591   GNUNET_CLIENT_receive (h->conn,
592                          &handle_replies,
593                          h,
594                          GNUNET_TIME_UNIT_FOREVER_REL);
595   h->in_replies = GNUNET_YES;
596   LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__);
597   return h;
598 }
599
600
601 /**
602  * Disconnect from the lockmanager service
603  *
604  * @param handle the handle to the lockmanager service
605  */
606 void
607 GNUNET_LOCKMANAGER_disconnect (struct GNUNET_LOCKMANAGER_Handle *handle)
608 {
609   struct MessageQueue *head;
610
611   LOG (GNUNET_ERROR_TYPE_DEBUG, "%s()\n", __func__);
612   if (0 != GNUNET_CONTAINER_multihashmap_size (handle->hashmap))
613   {
614     LOG (GNUNET_ERROR_TYPE_WARNING,
615          "Some locking requests are still present. Cancel them before "
616          "calling %s\n", __func__);
617     GNUNET_CONTAINER_multihashmap_iterate (handle->hashmap,
618                                            &free_iterator,
619                                            handle);
620   }
621   GNUNET_CONTAINER_multihashmap_destroy (handle->hashmap);
622   /* Clear the message queue */
623   if (NULL != handle->transmit_handle)
624   {
625     GNUNET_CLIENT_notify_transmit_ready_cancel (handle->transmit_handle);
626   }
627   head = handle->mq_head;
628   while (NULL != head)
629   {
630     GNUNET_CONTAINER_DLL_remove (handle->mq_head,
631                                  handle->mq_tail,
632                                  head);
633     GNUNET_free (head->msg);
634     GNUNET_free (head);
635     head = handle->mq_head;
636   }
637   GNUNET_CLIENT_disconnect (handle->conn);
638   GNUNET_free (handle);
639   LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__);
640 }
641
642
643 /**
644  * Tries to acquire the given lock(even if the lock has been lost) until the
645  * request is called. If the lock is available the status_cb will be
646  * called. If the lock is busy then the request is queued and status_cb
647  * will be called when the lock has been made available and acquired by us.
648  *
649  * @param handle the handle to the lockmanager service
650  *
651  * @param domain_name name of the locking domain. Clients who want to share
652  *          locks must use the same name for the locking domain. Also the
653  *          domain_name should be selected with the prefix
654  *          "GNUNET_<PROGRAM_NAME>_" to avoid domain name collisions.
655  *
656  *
657  * @param lock which lock to lock
658  *
659  * @param status_cb the callback for signalling when the lock is acquired and
660  *          when it is lost
661  *
662  * @param status_cb_cls the closure to the above callback
663  *
664  * @return the locking request handle for this request
665  */
666 struct GNUNET_LOCKMANAGER_LockingRequest *
667 GNUNET_LOCKMANAGER_acquire_lock (struct GNUNET_LOCKMANAGER_Handle *handle,
668                                  const char *domain_name,
669                                  uint32_t lock,
670                                  GNUNET_LOCKMANAGER_StatusCallback
671                                  status_cb,
672                                  void *status_cb_cls)
673 {
674   struct GNUNET_LOCKMANAGER_LockingRequest *r;
675   struct GNUNET_LOCKMANAGER_Message *msg;
676   struct GNUNET_HashCode hash;
677   size_t domain_name_length;
678   
679   LOG (GNUNET_ERROR_TYPE_DEBUG, "%s()\n", __func__);
680   r = GNUNET_malloc (sizeof (struct GNUNET_LOCKMANAGER_LockingRequest));
681   domain_name_length = strlen (domain_name) + 1;
682   r->handle = handle;
683   r->lock = lock;
684   r->domain = GNUNET_malloc (domain_name_length);
685   r->status = GNUNET_LOCKMANAGER_RELEASE;
686   r->status_cb = status_cb;
687   r->status_cb_cls = status_cb_cls;
688   memcpy (r->domain, domain_name, domain_name_length);
689   msg = generate_acquire_msg (r->domain, r->lock);
690   LOG (GNUNET_ERROR_TYPE_DEBUG, "Queueing ACQUIRE message\n");
691   queue_message (handle, msg);
692   get_key (r->domain, r->lock, &hash);
693   GNUNET_assert (GNUNET_OK == 
694                  GNUNET_CONTAINER_multihashmap_put (r->handle->hashmap,
695                                                     &hash,
696                                                     r,
697                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
698   LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__);
699   return r;
700 }
701
702
703 /**
704  * Function to cancel the locking request generated by
705  * GNUNET_LOCKMANAGER_acquire_lock. If the lock is acquired by us then the lock
706  * is released. GNUNET_LOCKMANAGER_StatusCallback will not be called upon any
707  * status changes resulting due to this call.
708  *
709  * @param request the LockingRequest to cancel
710  */
711 void
712 GNUNET_LOCKMANAGER_cancel_request (struct GNUNET_LOCKMANAGER_LockingRequest
713                                    *request)
714 {
715   struct GNUNET_LOCKMANAGER_Message *msg;
716   struct GNUNET_HashCode hash;
717   uint16_t msg_size;
718   size_t domain_name_length;
719
720   LOG (GNUNET_ERROR_TYPE_DEBUG, "%s()\n", __func__);
721   /* FIXME: Stop ACQUIRE retransmissions */
722   if (GNUNET_LOCKMANAGER_SUCCESS == request->status)
723   {
724     domain_name_length = strlen (request->domain) + 1;
725     msg_size = sizeof (struct GNUNET_LOCKMANAGER_Message) 
726       + domain_name_length;
727     msg = GNUNET_malloc (msg_size);
728     msg->header.type = htons (GNUNET_MESSAGE_TYPE_LOCKMANAGER_RELEASE);
729     msg->header.size = htons (msg_size);
730     msg->lock = htonl (request->lock);
731     memcpy (&msg[1], request->domain, domain_name_length);
732     queue_message (request->handle, msg);
733   }
734   get_key (request->domain, request->lock, &hash);
735   GNUNET_assert (GNUNET_YES ==
736                  GNUNET_CONTAINER_multihashmap_remove
737                  (request->handle->hashmap, &hash, request));
738   GNUNET_free (request->domain);
739   GNUNET_free (request);
740   LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__);
741 }