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