-fixing #2440 - cancel messages if RELEASE called when ACQUIRE still in queue
[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,
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   if (GNUNET_MESSAGE_TYPE_LOCKMANAGER_ACQUIRE
229       == ntohs (queue_entity->msg->header.type))
230   {
231     GNUNET_break (GNUNET_NO == queue_entity->lr->acquire_sent);
232     queue_entity->lr->acquire_sent = GNUNET_YES;
233     queue_entity->lr->mqe = NULL;
234   }
235   GNUNET_free (queue_entity->msg);  
236   GNUNET_CONTAINER_DLL_remove (handle->mq_head,
237                                handle->mq_tail,
238                                queue_entity);  
239   GNUNET_free (queue_entity);
240   queue_entity = handle->mq_head;
241   if (NULL != queue_entity)
242   {
243     handle->transmit_handle =
244       GNUNET_CLIENT_notify_transmit_ready (handle->conn,
245                                            ntohs
246                                            (queue_entity->msg->header.size),
247                                            TIMEOUT,
248                                            GNUNET_YES,
249                                            &transmit_notify,
250                                            handle);
251   }
252   if (GNUNET_NO == handle->in_replies)
253   {
254     handle->in_replies = GNUNET_YES;
255     GNUNET_CLIENT_receive (handle->conn,
256                            &handle_replies,
257                            handle,
258                            GNUNET_TIME_UNIT_FOREVER_REL);
259   }
260   return msg_size;
261 }
262
263
264 /**
265  * Queues a message into handle's send message queue
266  *
267  * @param handle the lockmanager handle whose queue will be used
268  * @param msg the message to be queued
269  * @param request the locking reqeust responsible for queueing this message
270  * @return the MessageQueue entity that has been queued
271  */
272 static struct MessageQueue *
273 queue_message (struct GNUNET_LOCKMANAGER_Handle *handle,
274                struct GNUNET_LOCKMANAGER_Message *msg,
275                struct GNUNET_LOCKMANAGER_LockingRequest *request)
276 {
277   struct MessageQueue *queue_entity;
278
279   GNUNET_assert (NULL != msg);
280   queue_entity = GNUNET_malloc (sizeof (struct MessageQueue));
281   queue_entity->msg = msg;
282   queue_entity->lr = request;
283   GNUNET_CONTAINER_DLL_insert_tail (handle->mq_head,
284                                     handle->mq_tail,
285                                     queue_entity);
286   if (NULL == handle->transmit_handle)
287   {
288     handle->transmit_handle =
289       GNUNET_CLIENT_notify_transmit_ready (handle->conn,
290                                            ntohs (msg->header.size),
291                                            TIMEOUT,
292                                            GNUNET_YES,
293                                            &transmit_notify,
294                                            handle);
295   }
296   return queue_entity;
297 }
298
299
300 /**
301  * Get the key for the given lock in the 'lock_map'.
302  *
303  * @param domain_name
304  * @param lock_number
305  * @param key set to the key
306  */
307 static void
308 get_key (const char *domain_name,
309          uint32_t lock_number,
310          struct GNUNET_HashCode *key)
311 {
312   uint32_t *last_32;
313
314   GNUNET_CRYPTO_hash (domain_name,
315                       strlen (domain_name),
316                       key);
317   last_32 = (uint32_t *) key;
318   *last_32 ^= lock_number;
319 }
320
321
322 /**
323  * Hashmap iterator for matching a LockingRequest
324  *
325  * @param cls the LockingRequestMatch structure
326  * @param key current key code
327  * @param value value in the hash map (struct GNUNET_LOCKMANAGER_LockingRequest)
328  * @return GNUNET_YES if we should continue to
329  *         iterate,
330  *         GNUNET_NO if not. 
331  */
332 static int
333 match_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
334 {
335   struct LockingRequestMatch *match = cls;
336   struct GNUNET_LOCKMANAGER_LockingRequest *lr = value;
337
338   if ( (match->lock == lr->lock) && (0 == strcmp (match->domain, lr->domain)) )
339   {
340     match->matched_entry = lr;
341     return GNUNET_NO;
342   }
343   return GNUNET_YES;
344 }
345
346
347 /**
348  * Function to find a LockingRequest associated with the given domain and lock
349  * attributes in the map
350  *
351  * @param map the map where the LockingRequests are stored
352  * @param domain the locking domain name
353  * @param lock the lock number
354  * @return the found LockingRequest; NULL if a matching LockingRequest wasn't
355  *           found 
356  */
357 static struct GNUNET_LOCKMANAGER_LockingRequest *
358 hashmap_find_lockingrequest (const struct GNUNET_CONTAINER_MultiHashMap *map,
359                              const char *domain,
360                              uint32_t lock)
361 {
362   struct GNUNET_HashCode hash;
363   struct LockingRequestMatch lock_match;
364
365   lock_match.matched_entry = NULL;
366   lock_match.domain = domain;
367   lock_match.lock = lock;
368   get_key (domain, lock, &hash);
369   GNUNET_CONTAINER_multihashmap_get_multiple (map,
370                                               &hash,
371                                               &match_iterator,
372                                               &lock_match);
373   return lock_match.matched_entry;
374 }
375
376
377 /**
378  * Task for calling status change callback for a lock
379  *
380  * @param cls the LockingRequest associated with this lock
381  * @param tc the TaskScheduler context
382  */
383 static void
384 call_status_cb_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
385 {
386   const struct GNUNET_LOCKMANAGER_LockingRequest *r = cls;
387
388   if (NULL != r->status_cb)
389   {
390     LOG (GNUNET_ERROR_TYPE_DEBUG,
391          "Calling status change for SUCCESS on lock num: %d, domain: %s\n",
392          r->lock, r->domain);
393     r->status_cb (r->status_cb_cls,
394                   r->domain,
395                   r->lock,
396                   r->status);
397   }
398 }
399
400
401 /**
402  * Function to generate acquire message for a lock
403  *
404  * @param domain_name the domain name of the lock
405  * @param lock the lock number
406  * @return the generated GNUNET_LOCKMANAGER_Message
407  */
408 static struct GNUNET_LOCKMANAGER_Message *
409 generate_acquire_msg (const char *domain_name, uint32_t lock)
410 {
411   struct GNUNET_LOCKMANAGER_Message *msg;
412   size_t domain_name_len;
413   uint16_t  msg_size;
414   
415   domain_name_len = strlen (domain_name) + 1;
416   msg_size = sizeof (struct GNUNET_LOCKMANAGER_Message) + domain_name_len;
417   msg = GNUNET_malloc (msg_size);
418   msg->header.type = htons (GNUNET_MESSAGE_TYPE_LOCKMANAGER_ACQUIRE);
419   msg->header.size = htons (msg_size);
420   msg->lock = htonl (lock);
421   memcpy (&msg[1], domain_name, domain_name_len);
422   return msg;
423 }
424
425
426 /**
427  * Iterator to call relase on locks; acquire messages are sent for all
428  * locks. In addition, if a lock is acquired before, it is not released and its
429  * status callback is called to signal its release
430  *
431  * @param cls the lockmanager handle
432  * @param key current key code
433  * @param value the Locking request
434  * @return GNUNET_YES if we should continue to
435  *         iterate,
436  *         GNUNET_NO if not.
437  */
438 static int
439 release_n_retry_iterator (void *cls,
440                           const struct GNUNET_HashCode * key,
441                           void *value)
442 {
443   struct GNUNET_LOCKMANAGER_LockingRequest *r = value;
444   struct GNUNET_LOCKMANAGER_Handle *h = cls;
445   struct GNUNET_LOCKMANAGER_Message *msg;
446
447   if (GNUNET_NO == r->acquire_sent) /* an acquire is still in queue */
448     return GNUNET_YES;
449   r->acquire_sent = GNUNET_NO;
450   msg = generate_acquire_msg (r->domain, r->lock);
451   r->mqe = queue_message (h, msg, r);
452   if (GNUNET_LOCKMANAGER_RELEASE == r->status)
453     return GNUNET_YES;
454   if (NULL != r->status_cb)
455   {
456     LOG (GNUNET_ERROR_TYPE_DEBUG,
457          "Calling status change for RELEASE on lock num: %d, domain: %s\n",
458          r->lock, r->domain);
459     r->status = GNUNET_LOCKMANAGER_RELEASE;
460     r->status_cb (r->status_cb_cls,
461                   r->domain,
462                   r->lock,
463                   GNUNET_LOCKMANAGER_RELEASE);
464   }
465   return GNUNET_YES;
466 }
467
468
469 /**
470  * Handler for server replies
471  *
472  * @param cls the LOCKMANAGER_Handle
473  * @param msg received message, NULL on timeout or fatal error
474  */
475 static void 
476 handle_replies (void *cls,
477                 const struct GNUNET_MessageHeader *msg)
478 {
479   struct GNUNET_LOCKMANAGER_Handle *handle = cls;
480   const struct GNUNET_LOCKMANAGER_Message *m;
481   struct GNUNET_LOCKMANAGER_LockingRequest *lr;
482   const char *domain;
483   struct GNUNET_HashCode hash;
484   uint32_t lock;
485   uint16_t msize;
486
487   handle->in_replies = GNUNET_NO;
488   if (NULL == msg)
489   {
490     LOG (GNUNET_ERROR_TYPE_DEBUG,
491          "Lockmanager service not available or went down\n");    
492     /* Should release all locks and retry to acquire them */
493     GNUNET_CONTAINER_multihashmap_iterate (handle->hashmap,
494                                            &release_n_retry_iterator,
495                                            handle);
496     return;
497   }
498   handle->in_replies = GNUNET_YES;
499   GNUNET_CLIENT_receive (handle->conn,
500                          &handle_replies,
501                          handle,
502                          GNUNET_TIME_UNIT_FOREVER_REL);
503   if (GNUNET_MESSAGE_TYPE_LOCKMANAGER_SUCCESS != ntohs(msg->type))
504   {
505     GNUNET_break (0);
506     return;
507   }
508   msize = ntohs (msg->size);
509   if (msize <= sizeof (struct GNUNET_LOCKMANAGER_Message))
510   {
511     GNUNET_break (0);
512     return;
513   }
514   m = (const struct GNUNET_LOCKMANAGER_Message *) msg;
515   domain = (const char *) &m[1];
516   msize -= sizeof (struct GNUNET_LOCKMANAGER_Message);
517   if ('\0' != domain[msize-1])
518   {
519     GNUNET_break (0);
520     return;
521   }
522
523   lock = ntohl (m->lock);
524   get_key (domain, lock, &hash);      
525   LOG (GNUNET_ERROR_TYPE_DEBUG,
526        "Received SUCCESS message for lock: %d, domain %s\n",
527        lock, domain);
528   if (NULL == (lr = hashmap_find_lockingrequest (handle->hashmap,
529                                                  domain,
530                                                  lock)))
531   {
532     GNUNET_break (0);
533     return;
534   }
535   if (GNUNET_LOCKMANAGER_SUCCESS == lr->status)
536   {
537     GNUNET_break (0);
538     return;
539   }
540   LOG (GNUNET_ERROR_TYPE_DEBUG,
541        "Changing status for lock: %d in domain: %s to SUCCESS\n",
542        lr->lock, lr->domain);
543   lr->status = GNUNET_LOCKMANAGER_SUCCESS;
544   GNUNET_SCHEDULER_add_continuation (&call_status_cb_task,
545                                      lr,
546                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
547 }
548
549
550 /**
551  * Iterator to free hash map entries.
552  *
553  * @param cls the lockmanger handle
554  * @param key current key code
555  * @param value the Locking request
556  * @return GNUNET_YES if we should continue to
557  *         iterate,
558  *         GNUNET_NO if not.
559  */
560 static int
561 free_iterator(void *cls,
562               const struct GNUNET_HashCode * key,
563               void *value)
564 {
565   struct GNUNET_LOCKMANAGER_Handle *h = cls;
566   struct GNUNET_LOCKMANAGER_LockingRequest *r = value;
567
568   LOG (GNUNET_ERROR_TYPE_DEBUG,
569        "Clearing locking request\n");
570   GNUNET_assert (GNUNET_YES == 
571                  GNUNET_CONTAINER_multihashmap_remove (h->hashmap,
572                                                        key,
573                                                        value));
574   GNUNET_free (r->domain);
575   GNUNET_free (r);
576   return GNUNET_YES;
577 }
578
579
580 /*******************/
581 /* API Definitions */
582 /*******************/
583
584
585 /**
586  * Connect to the lockmanager service
587  *
588  * @param cfg the configuration to use
589  *
590  * @return upon success the handle to the service; NULL upon error
591  */
592 struct GNUNET_LOCKMANAGER_Handle *
593 GNUNET_LOCKMANAGER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
594 {
595   struct GNUNET_LOCKMANAGER_Handle *h;
596
597   LOG (GNUNET_ERROR_TYPE_DEBUG, "%s()\n", __func__);
598   h = GNUNET_malloc (sizeof (struct GNUNET_LOCKMANAGER_Handle));
599   h->conn = GNUNET_CLIENT_connect ("lockmanager", cfg);
600   if (NULL == h->conn)
601   {
602     GNUNET_free (h);
603     LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__);
604     return NULL;
605   }  
606   h->hashmap = GNUNET_CONTAINER_multihashmap_create (15);
607   GNUNET_assert (NULL != h->hashmap);
608   h->in_replies = GNUNET_YES;
609   GNUNET_CLIENT_receive (h->conn,
610                          &handle_replies,
611                          h,
612                          GNUNET_TIME_UNIT_FOREVER_REL);  
613   LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__);
614   return h;
615 }
616
617
618 /**
619  * Disconnect from the lockmanager service
620  *
621  * @param handle the handle to the lockmanager service
622  */
623 void
624 GNUNET_LOCKMANAGER_disconnect (struct GNUNET_LOCKMANAGER_Handle *handle)
625 {
626   struct MessageQueue *head;
627
628   LOG (GNUNET_ERROR_TYPE_DEBUG, "%s()\n", __func__);
629   if (0 != GNUNET_CONTAINER_multihashmap_size (handle->hashmap))
630   {
631     LOG (GNUNET_ERROR_TYPE_WARNING,
632          "Some locking requests are still present. Cancel them before "
633          "calling %s\n", __func__);
634     GNUNET_CONTAINER_multihashmap_iterate (handle->hashmap,
635                                            &free_iterator,
636                                            handle);
637   }
638   GNUNET_CONTAINER_multihashmap_destroy (handle->hashmap);
639   /* Clear the message queue */
640   if (NULL != handle->transmit_handle)
641   {
642     GNUNET_CLIENT_notify_transmit_ready_cancel (handle->transmit_handle);
643   }
644   head = handle->mq_head;
645   while (NULL != head)
646   {
647     GNUNET_CONTAINER_DLL_remove (handle->mq_head,
648                                  handle->mq_tail,
649                                  head);
650     GNUNET_free (head->msg);
651     GNUNET_free (head);
652     head = handle->mq_head;
653   }
654   GNUNET_CLIENT_disconnect (handle->conn);
655   GNUNET_free (handle);
656   LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__);
657 }
658
659
660 /**
661  * Tries to acquire the given lock(even if the lock has been lost) until the
662  * request is called. If the lock is available the status_cb will be
663  * called. If the lock is busy then the request is queued and status_cb
664  * will be called when the lock has been made available and acquired by us.
665  *
666  * @param handle the handle to the lockmanager service
667  *
668  * @param domain_name name of the locking domain. Clients who want to share
669  *          locks must use the same name for the locking domain. Also the
670  *          domain_name should be selected with the prefix
671  *          "GNUNET_<PROGRAM_NAME>_" to avoid domain name collisions.
672  *
673  *
674  * @param lock which lock to lock
675  *
676  * @param status_cb the callback for signalling when the lock is acquired and
677  *          when it is lost
678  *
679  * @param status_cb_cls the closure to the above callback
680  *
681  * @return the locking request handle for this request
682  */
683 struct GNUNET_LOCKMANAGER_LockingRequest *
684 GNUNET_LOCKMANAGER_acquire_lock (struct GNUNET_LOCKMANAGER_Handle *handle,
685                                  const char *domain_name,
686                                  uint32_t lock,
687                                  GNUNET_LOCKMANAGER_StatusCallback
688                                  status_cb,
689                                  void *status_cb_cls)
690 {
691   struct GNUNET_LOCKMANAGER_LockingRequest *r;
692   struct GNUNET_LOCKMANAGER_Message *msg;
693   struct GNUNET_HashCode hash;
694   size_t domain_name_length;
695   
696   LOG (GNUNET_ERROR_TYPE_DEBUG, "%s()\n", __func__);
697   r = GNUNET_malloc (sizeof (struct GNUNET_LOCKMANAGER_LockingRequest));
698   domain_name_length = strlen (domain_name) + 1;
699   r->handle = handle;
700   r->lock = lock;
701   r->domain = GNUNET_malloc (domain_name_length);
702   r->status = GNUNET_LOCKMANAGER_RELEASE;
703   r->status_cb = status_cb;
704   r->status_cb_cls = status_cb_cls;
705   r->acquire_sent = GNUNET_NO;
706   memcpy (r->domain, domain_name, domain_name_length);
707   msg = generate_acquire_msg (r->domain, r->lock);
708   LOG (GNUNET_ERROR_TYPE_DEBUG, "Queueing ACQUIRE message\n");  
709   r->mqe = queue_message (handle, msg, r);
710   get_key (r->domain, r->lock, &hash);
711   GNUNET_assert (GNUNET_OK == 
712                  GNUNET_CONTAINER_multihashmap_put (r->handle->hashmap,
713                                                     &hash,
714                                                     r,
715                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
716   LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__);
717   return r;
718 }
719
720
721 /**
722  * Function to cancel the locking request generated by
723  * GNUNET_LOCKMANAGER_acquire_lock. If the lock is acquired by us then the lock
724  * is released. GNUNET_LOCKMANAGER_StatusCallback will not be called upon any
725  * status changes resulting due to this call.
726  *
727  * @param request the LockingRequest to cancel
728  */
729 void
730 GNUNET_LOCKMANAGER_cancel_request (struct GNUNET_LOCKMANAGER_LockingRequest
731                                    *request)
732 {
733   struct GNUNET_LOCKMANAGER_Message *msg;
734   struct GNUNET_HashCode hash;
735   uint16_t msg_size;
736   size_t domain_name_length;
737
738   LOG (GNUNET_ERROR_TYPE_DEBUG, "%s()\n", __func__);
739   if (GNUNET_NO == request->acquire_sent)
740   {
741     GNUNET_assert (NULL != request->mqe);
742     if ((NULL != request->handle->transmit_handle) 
743         && (request->handle->mq_head == request->mqe))
744     {
745       GNUNET_CLIENT_notify_transmit_ready_cancel
746         (request->handle->transmit_handle);
747       request->handle->transmit_handle = NULL;
748     }      
749     GNUNET_CONTAINER_DLL_remove (request->handle->mq_head,
750                                  request->handle->mq_tail,
751                                  request->mqe);
752     GNUNET_free (request->mqe->msg);
753     GNUNET_free (request->mqe);
754     request->status = GNUNET_LOCKMANAGER_RELEASE;
755   }
756   if (GNUNET_LOCKMANAGER_SUCCESS == request->status)
757   {
758     domain_name_length = strlen (request->domain) + 1;
759     msg_size = sizeof (struct GNUNET_LOCKMANAGER_Message) 
760       + domain_name_length;
761     msg = GNUNET_malloc (msg_size);
762     msg->header.type = htons (GNUNET_MESSAGE_TYPE_LOCKMANAGER_RELEASE);
763     msg->header.size = htons (msg_size);
764     msg->lock = htonl (request->lock);
765     memcpy (&msg[1], request->domain, domain_name_length);
766     GNUNET_assert (NULL == request->mqe);
767     (void) queue_message (request->handle, msg, request);
768   }
769   get_key (request->domain, request->lock, &hash);
770   GNUNET_assert (GNUNET_YES ==
771                  GNUNET_CONTAINER_multihashmap_remove
772                  (request->handle->hashmap, &hash, request));
773   GNUNET_free (request->domain);
774   GNUNET_free (request);
775   LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__);
776 }
777
778 /* end of lockmanager_api.c */