- verboser log, faster start
[oweals/gnunet.git] / src / lockmanager / gnunet-service-lockmanager.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/gnunet-service-lockmanager.c
23  * @brief implementation of the LOCKMANAGER service
24  * @author Sree Harsha Totakura
25  */
26
27 #include "platform.h"
28 #include "gnunet_common.h"
29 #include "gnunet_container_lib.h"
30 #include "gnunet_protocols.h"
31 #include "gnunet_service_lib.h"
32 #include "gnunet_server_lib.h"
33
34 #include "lockmanager.h"
35
36
37 #define LOG(kind,...)                           \
38   GNUNET_log (kind, __VA_ARGS__)
39
40 #define TIME_REL_MINS(min)                                      \
41   GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, min)
42
43 #define TIMEOUT TIME_REL_MINS(3)
44
45
46 /**
47  * Doubly linked list of clients having connections to us
48  */
49 struct ClientList;
50
51
52 /**
53  * Doubly linked list of clients waiting for a lock
54  */
55 struct WaitList
56 {
57   /**
58    * The next client structure
59    */
60   struct WaitList *next;
61
62   /**
63    * The prev client structure
64    */
65   struct WaitList *prev;
66
67   /**
68    * Pointer to the client
69    */
70   struct ClientList *cl_entry;
71 };
72
73
74 /**
75  * Structure representing a Lock
76  */
77 struct Lock
78 {
79   /**
80    * List head of clients waiting for this lock
81    */
82   struct WaitList *wl_head;
83
84   /**
85    * List tail of clients waiting for this lock
86    */
87   struct WaitList *wl_tail;
88
89   /**
90    * The client which is currently holding this lock
91    */
92   struct ClientList *cl_entry;
93
94   /**
95    * The name of the locking domain this lock belongs to
96    */
97   char *domain_name;
98
99   /**
100    * The number of this lock
101    */
102   uint32_t lock_num;
103 };
104
105
106 /**
107  * A Lock element for a doubly linked list
108  */
109 struct LockList
110 {
111   /**
112    * The next element pointer
113    */
114   struct LockList *next;
115
116   /**
117    * Pointer to the previous element
118    */
119   struct LockList *prev;
120
121   /**
122    * Pointer to the Lock
123    */
124   struct Lock *lock;
125 };
126
127
128 /**
129  * Doubly linked list of clients having connections to us
130  */
131 struct ClientList
132 {
133
134   /**
135    * The next client structure
136    */
137   struct ClientList *next;
138
139   /**
140    * The previous client structure
141    */
142   struct ClientList *prev;
143
144   /**
145    * Head of the doubly linked list of the currently held locks by this client
146    */
147   struct LockList *ll_head;
148
149   /**
150    * Tail of the doubly linked list of the currently held locks by this client
151    */
152   struct LockList *ll_tail;
153
154   /**
155    * Pointer to the client
156    */
157   struct GNUNET_SERVER_Client *client;
158 };
159
160
161 /**
162  * Structure for matching a lock
163  */
164 struct LockMatch
165 {
166   /**
167    * The matched LockingRequest entry; Should be NULL if no entry is found
168    */
169   struct Lock *matched_entry;
170
171   /**
172    * The locking domain name of the lock
173    */
174   const char *domain_name;
175
176   /**
177    * The lock number
178    */
179   uint32_t lock_num;
180 };
181
182
183 /**
184  * Map of lock-keys to the 'struct LockList' entry for the key.
185  */
186 static struct GNUNET_CONTAINER_MultiHashMap *lock_map;
187
188 /**
189  * Head of the doubly linked list of clients currently connected
190  */
191 static struct ClientList *cl_head;
192
193 /**
194  * Tail of the doubly linked list of clients currently connected
195  */
196 static struct ClientList *cl_tail;
197
198
199 /**
200  * Get the key for the given lock in the 'lock_map'.
201  *
202  * @param domain_name
203  * @param lock_number
204  * @param key set to the key
205  */
206 static void
207 get_key (const char *domain_name, uint32_t lock_number,
208          struct GNUNET_HashCode *key)
209 {
210   uint32_t *last_32;
211
212   GNUNET_CRYPTO_hash (domain_name, strlen (domain_name), key);
213   last_32 = (uint32_t *) key;
214   *last_32 ^= lock_number;
215 }
216
217
218 /**
219  * Hashmap iterator for matching a lock
220  *
221  * @param cls the LockMatch structure
222  * @param key current key code
223  * @param value value in the hash map (struct Lock)
224  * @return GNUNET_YES if we should continue to
225  *         iterate,
226  *         GNUNET_NO if not.
227  */
228 static int
229 match_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
230 {
231   struct LockMatch *match = cls;
232   struct Lock *lock = value;
233
234   if ((match->lock_num == lock->lock_num) &&
235       (0 == strcmp (match->domain_name, lock->domain_name)))
236   {
237     match->matched_entry = lock;
238     return GNUNET_NO;
239   }
240   return GNUNET_YES;
241 }
242
243
244 /**
245  * Function to search for a lock in the global lock hashmap
246  *
247  * @param domain_name the name of the locking domain
248  * @param lock_num the number of the lock
249  * @return the lock if found; NULL if not
250  */
251 static struct Lock *
252 find_lock (const char *domain_name, const uint32_t lock_num)
253 {
254   struct LockMatch match;
255   struct GNUNET_HashCode key;
256
257   match.lock_num = lock_num;
258   match.domain_name = domain_name;
259   match.matched_entry = NULL;
260   get_key (domain_name, lock_num, &key);
261   GNUNET_CONTAINER_multihashmap_get_multiple (lock_map, &key, &match_iterator,
262                                               &match);
263   return match.matched_entry;
264 }
265
266
267 /**
268  * Adds a lock to the global lock hashmap
269  *
270  * @param domain_name the name of the lock's locking domain
271  * @param lock_num the lock number
272  * @return pointer to the lock structure which is added to lock map
273  */
274 static struct Lock *
275 add_lock (const char *domain_name, uint32_t lock_num)
276 {
277   struct Lock *lock;
278   struct GNUNET_HashCode key;
279   size_t domain_name_len;
280
281   lock = GNUNET_malloc (sizeof (struct Lock));
282   domain_name_len = strlen (domain_name) + 1;
283   lock->domain_name = GNUNET_malloc (domain_name_len);
284   strncpy (lock->domain_name, domain_name, domain_name_len);
285   lock->lock_num = lock_num;
286   get_key (domain_name, lock_num, &key);
287   LOG (GNUNET_ERROR_TYPE_DEBUG,
288        "Adding a lock with num: %d and domain: %s to the lock map\n",
289        lock->lock_num, lock->domain_name);
290   GNUNET_CONTAINER_multihashmap_put (lock_map, &key, lock,
291                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
292   return lock;
293 }
294
295
296 /**
297  * Removes a lock from the lock map. The WaitList of the lock should be empty
298  *
299  * @param lock the lock to remove
300  */
301 static void
302 remove_lock (struct Lock *lock)
303 {
304   struct GNUNET_HashCode key;
305
306   GNUNET_assert (NULL == lock->wl_head);
307   get_key (lock->domain_name, lock->lock_num, &key);
308   LOG (GNUNET_ERROR_TYPE_DEBUG,
309        "Removing lock with num: %u, domain: %s from lock map\n", lock->lock_num,
310        lock->domain_name);
311   GNUNET_assert (GNUNET_YES ==
312                  GNUNET_CONTAINER_multihashmap_remove (lock_map, &key, lock));
313   GNUNET_free (lock->domain_name);
314   GNUNET_free (lock);
315 }
316
317
318 /**
319  * Find the LockList entry corresponding to the given Lock in a ClientList
320  * entry
321  *
322  * @param cl_entry the ClientList entry whose lock list has to be searched
323  * @param lock the lock which has to be matched
324  * @return the matching LockList entry; NULL if no match is found
325  */
326 static struct LockList *
327 cl_ll_find_lock (struct ClientList *cl_entry, const struct Lock *lock)
328 {
329   struct LockList *ll_entry;
330
331   for (ll_entry = cl_entry->ll_head; NULL != ll_entry;
332        ll_entry = ll_entry->next)
333   {
334     if (lock == ll_entry->lock)
335       return ll_entry;
336   }
337   return NULL;
338 }
339
340
341 /**
342  * Function to append a lock to the lock list of a ClientList entry
343  *
344  * @param cl_entry the client which currently owns this lock
345  * @param lock the lock to be added to the cl_entry's lock list
346  */
347 static void
348 cl_ll_add_lock (struct ClientList *cl_entry, struct Lock *lock)
349 {
350   struct LockList *ll_entry;
351
352   ll_entry = GNUNET_malloc (sizeof (struct LockList));
353   ll_entry->lock = lock;
354   LOG (GNUNET_ERROR_TYPE_DEBUG,
355        "Adding a lock with num: %u and domain: %s to lock list\n",
356        lock->lock_num, lock->domain_name);
357   GNUNET_CONTAINER_DLL_insert_tail (cl_entry->ll_head, cl_entry->ll_tail,
358                                     ll_entry);
359 }
360
361
362 /**
363  * Function to delete a lock from the lock list of the given ClientList entry
364  *
365  * @param cl_entry the ClientList entry
366  * @param ll_entry the LockList entry to be deleted
367  */
368 static void
369 cl_ll_remove_lock (struct ClientList *cl_entry, struct LockList *ll_entry)
370 {
371   LOG (GNUNET_ERROR_TYPE_DEBUG,
372        "Removing lock with num: %u, domain: %s from lock list of a client\n",
373        ll_entry->lock->lock_num, ll_entry->lock->domain_name);
374   GNUNET_assert (NULL != cl_entry->ll_head);
375   GNUNET_CONTAINER_DLL_remove (cl_entry->ll_head, cl_entry->ll_tail, ll_entry);
376   GNUNET_free (ll_entry);
377 }
378
379
380 /**
381  * Find a WaitList entry in the waiting list of a lock
382  *
383  * @param lock the lock whose wait list has to be searched
384  * @param cl_entry the ClientList entry to be searched
385  * @return the WaitList entry matching the given cl_entry; NULL if not match
386  *           was found
387  */
388 static struct WaitList *
389 lock_wl_find (const struct Lock *lock, const struct ClientList *cl_entry)
390 {
391   struct WaitList *wl_entry;
392
393   for (wl_entry = lock->wl_head; NULL != wl_entry; wl_entry = wl_entry->next)
394   {
395     if (cl_entry == wl_entry->cl_entry)
396       return wl_entry;
397   }
398   return NULL;
399 }
400
401
402 /**
403  * Add a client to the wait list of given lock
404  *
405  * @param lock the lock list entry of a lock
406  * @param cl_entry the client to queue for the lock's wait list
407  */
408 static void
409 lock_wl_add_client (struct Lock *lock, struct ClientList *cl_entry)
410 {
411   struct WaitList *wl_entry;
412
413   LOG (GNUNET_ERROR_TYPE_DEBUG,
414        "Adding a client to lock's wait list (lock num: %u, domain: %s)\n",
415        lock->lock_num, lock->domain_name);
416   wl_entry = GNUNET_malloc (sizeof (struct WaitList));
417   wl_entry->cl_entry = cl_entry;
418   GNUNET_CONTAINER_DLL_insert_tail (lock->wl_head, lock->wl_tail, wl_entry);
419 }
420
421
422 /**
423  * Remove an entry from the wait list of the given lock
424  *
425  * @param lock the lock
426  * @param wl_entry the wait list entry to be removed
427  */
428 static void
429 lock_wl_remove (struct Lock *lock, struct WaitList *wl_entry)
430 {
431   LOG (GNUNET_ERROR_TYPE_DEBUG,
432        "Removing client from wait list of lock with num: %u, domain: %s\n",
433        lock->lock_num, lock->domain_name);
434   GNUNET_CONTAINER_DLL_remove (lock->wl_head, lock->wl_tail, wl_entry);
435   GNUNET_free (wl_entry);
436 }
437
438
439 /**
440  * Search for a client in the client list
441  *
442  * @param client the client to be searched for
443  * @return the ClientList entry; NULL if the client is not found
444  */
445 static struct ClientList *
446 cl_find_client (const struct GNUNET_SERVER_Client *client)
447 {
448   struct ClientList *current;
449
450   for (current = cl_head; NULL != current; current = current->next)
451     if (client == current->client)
452       return current;
453   return NULL;
454 }
455
456
457 /**
458  * Append a client to the client list
459  *
460  * @param client the client to be appended to the list
461  * @return the client list entry which is added to the client list
462  */
463 static struct ClientList *
464 cl_add_client (struct GNUNET_SERVER_Client *client)
465 {
466   struct ClientList *new_client;
467
468   LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding a client to the client list\n");
469   new_client = GNUNET_malloc (sizeof (struct ClientList));
470   GNUNET_SERVER_client_keep (client);
471   new_client->client = client;
472   GNUNET_CONTAINER_DLL_insert_tail (cl_head, cl_tail, new_client);
473   return new_client;
474 }
475
476
477 /**
478  * Delete the given client from the client list. The LockList should be empty
479  *
480  * @param cl_entry the client list entry to delete
481  */
482 static void
483 cl_remove_client (struct ClientList *cl_entry)
484 {
485   GNUNET_assert (NULL == cl_entry->ll_head);
486   LOG (GNUNET_ERROR_TYPE_DEBUG, "Removing a client from the client list\n");
487   GNUNET_SERVER_client_drop (cl_entry->client);
488   GNUNET_CONTAINER_DLL_remove (cl_head, cl_tail, cl_entry);
489   GNUNET_free (cl_entry);
490 }
491
492
493 /**
494  * Transmit notify for sending message to client
495  *
496  * @param cls the message to send
497  * @param size number of bytes available in buf
498  * @param buf where the callee should write the message
499  * @return number of bytes written to buf
500  */
501 static size_t
502 transmit_notify (void *cls, size_t size, void *buf)
503 {
504   struct GNUNET_LOCKMANAGER_Message *msg = cls;
505   uint16_t msg_size;
506
507   if ((0 == size) || (NULL == buf))
508   {
509     /* FIXME: Timed out -- requeue? */
510     return 0;
511   }
512   msg_size = ntohs (msg->header.size);
513   GNUNET_assert (size >= msg_size);
514   memcpy (buf, msg, msg_size);
515   GNUNET_free (msg);
516   LOG (GNUNET_ERROR_TYPE_DEBUG, "Message of size %u sent\n", msg_size);
517   return msg_size;
518 }
519
520
521 /**
522  * Send SUCCESS message to the client
523  *
524  * @param client the client to which the message has to be sent
525  * @param domain_name the locking domain of the successfully acquried lock
526  * @param lock_num the number of the successfully acquired lock
527  */
528 static void
529 send_success_msg (struct GNUNET_SERVER_Client *client, const char *domain_name,
530                   int lock_num)
531 {
532   struct GNUNET_LOCKMANAGER_Message *reply;
533   size_t domain_name_len;
534   uint16_t reply_size;
535
536   domain_name_len = strlen (domain_name) + 1;
537   reply_size = sizeof (struct GNUNET_LOCKMANAGER_Message) + domain_name_len;
538   reply = GNUNET_malloc (reply_size);
539   reply->header.size = htons (reply_size);
540   reply->header.type = htons (GNUNET_MESSAGE_TYPE_LOCKMANAGER_SUCCESS);
541   reply->lock = htonl (lock_num);
542   strncpy ((char *) &reply[1], domain_name, domain_name_len);
543   LOG (GNUNET_ERROR_TYPE_DEBUG,
544        "Sending SUCCESS message for lock with num: %u, domain: %s\n", lock_num,
545        domain_name);
546   GNUNET_SERVER_notify_transmit_ready (client, reply_size, TIMEOUT,
547                                        &transmit_notify, reply);
548 }
549
550
551 /**
552  * Handler for GNUNET_MESSAGE_TYPE_LOCKMANAGER_ACQUIRE
553  *
554  * @param cls NULL
555  * @param client the client sending this message
556  * @param message GNUNET_MESSAGE_TYPE_LOCKMANAGER_ACQUIRE message
557  */
558 static void
559 handle_acquire (void *cls, struct GNUNET_SERVER_Client *client,
560                 const struct GNUNET_MessageHeader *message)
561 {
562   const struct GNUNET_LOCKMANAGER_Message *request;
563   const char *domain_name;
564   struct Lock *lock;
565   struct ClientList *cl_entry;
566   uint32_t lock_num;
567   uint16_t msize;
568
569   msize = htons (message->size);
570   if (msize <= sizeof (struct GNUNET_LOCKMANAGER_Message))
571   {
572     GNUNET_break (0);
573     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
574     return;
575   }
576   request = (struct GNUNET_LOCKMANAGER_Message *) message;
577   domain_name = (const char *) &request[1];
578   msize -= sizeof (struct GNUNET_LOCKMANAGER_Message);
579   if ('\0' != domain_name[msize - 1])
580   {
581     LOG (GNUNET_ERROR_TYPE_DEBUG,
582          "Bad domain `%.*s' - byte with index %u is %X, not 0.\n", msize,
583          domain_name, msize - 1, (unsigned int) domain_name[msize - 1]);
584     GNUNET_break (0);
585     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
586     return;
587   }
588   lock_num = ntohl (request->lock);
589   LOG (GNUNET_ERROR_TYPE_DEBUG,
590        "Received an ACQUIRE message for lock num: %u domain: %s\n", lock_num,
591        domain_name);
592   if (NULL == (cl_entry = cl_find_client (client)))
593     cl_entry = cl_add_client (client);  /* Add client if not in client list */
594   if (NULL != (lock = find_lock (domain_name, lock_num)))
595   {
596     if (lock->cl_entry == cl_entry)
597     {                           /* Client is requesting a lock it already owns */
598       GNUNET_break_op (0);
599       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
600       return;
601     }
602     lock_wl_add_client (lock, cl_entry);
603     cl_ll_add_lock (cl_entry, lock);
604   }
605   else                          /* Lock not present */
606   {
607     lock = add_lock (domain_name, lock_num);
608     lock->cl_entry = cl_entry;
609     cl_ll_add_lock (cl_entry, lock);
610     send_success_msg (cl_entry->client, domain_name, lock_num);
611   }
612   GNUNET_SERVER_receive_done (client, GNUNET_OK);
613 }
614
615
616 /**
617  * This function gives the lock to the first client in the wait list of the
618  * lock. If no clients are currently waiting for this lock, the lock is then
619  * destroyed.
620  *
621  * @param lock the lock which has to be processed for release
622  */
623 static void
624 process_lock_release (struct Lock *lock)
625 {
626   struct WaitList *wl_entry;
627
628   LOG (GNUNET_ERROR_TYPE_DEBUG,
629        "Processing lock release for lock with num: %u, domain: %s\n",
630        lock->lock_num, lock->domain_name);
631   wl_entry = lock->wl_head;
632   if (NULL == wl_entry)
633   {
634     remove_lock (lock);         /* No clients waiting for this lock - delete */
635     return;
636   }
637   LOG (GNUNET_ERROR_TYPE_DEBUG, "Giving lock to a client from wait list\n");
638   lock->cl_entry = wl_entry->cl_entry;
639   lock_wl_remove (lock, wl_entry);
640   send_success_msg (lock->cl_entry->client, lock->domain_name, lock->lock_num);
641 }
642
643
644 /**
645  * Handle for GNUNET_MESSAGE_TYPE_LOCKMANAGER_RELEASE
646  *
647  * @param cls NULL
648  * @param client the client sending this message
649  * @param message the LOCKMANAGER_RELEASE message
650  */
651 static void
652 handle_release (void *cls, struct GNUNET_SERVER_Client *client,
653                 const struct GNUNET_MessageHeader *message)
654 {
655   const struct GNUNET_LOCKMANAGER_Message *request;
656   struct ClientList *cl_entry;
657   struct WaitList *wl_entry;
658   struct LockList *ll_entry;
659   const char *domain_name;
660   struct Lock *lock;
661   uint32_t lock_num;
662   uint16_t msize;
663
664   msize = ntohs (message->size);
665   if (msize <= sizeof (struct GNUNET_LOCKMANAGER_Message))
666   {
667     GNUNET_break (0);
668     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
669     return;
670   }
671   request = (const struct GNUNET_LOCKMANAGER_Message *) message;
672   domain_name = (const char *) &request[1];
673   msize -= sizeof (struct GNUNET_LOCKMANAGER_Message);
674   if ('\0' != domain_name[msize - 1])
675   {
676     GNUNET_break (0);
677     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
678     return;
679
680
681   }
682   lock_num = ntohl (request->lock);
683   LOG (GNUNET_ERROR_TYPE_DEBUG,
684        "Received RELEASE message for lock with num: %d, domain: %s\n", lock_num,
685        domain_name);
686   if (NULL == (cl_entry = cl_find_client (client)))
687   {
688     GNUNET_break (0);
689     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
690     return;
691   }
692   lock = find_lock (domain_name, lock_num);
693   if (NULL == lock)
694   {
695     GNUNET_break (0);
696     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
697     return;
698   }
699   if (NULL == (ll_entry = cl_ll_find_lock (cl_entry, lock)))
700   {
701     GNUNET_break (0);
702     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
703     return;
704   }
705   cl_ll_remove_lock (cl_entry, ll_entry);
706   if (cl_entry == lock->cl_entry)
707   {
708     process_lock_release (lock);
709     GNUNET_SERVER_receive_done (client, GNUNET_OK);
710     return;
711   }
712   /* remove 'client' from wait list (check that it is not there...) */
713   if (NULL != (wl_entry = lock_wl_find (lock, cl_entry)))
714   {
715     lock_wl_remove (lock, wl_entry);
716   }
717   GNUNET_SERVER_receive_done (client, GNUNET_OK);
718 }
719
720
721 /**
722  * Callback for client disconnect
723  *
724  * @param cls NULL
725  * @param client the client which has disconnected
726  */
727 static void
728 client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
729 {
730   struct ClientList *cl_entry;
731   struct LockList *ll_entry;
732   struct Lock *lock;
733   struct WaitList *wl_entry;
734
735   if (NULL == client)
736     return;
737   LOG (GNUNET_ERROR_TYPE_DEBUG,
738        "A client has been disconnected -- freeing its locks and resources\n");
739   cl_entry = cl_find_client (client);
740   if (NULL == cl_entry)
741     return;
742   while (NULL != (ll_entry = cl_entry->ll_head))
743   {
744     lock = ll_entry->lock;
745     cl_ll_remove_lock (cl_entry, ll_entry);
746     if (lock->cl_entry == cl_entry)
747       process_lock_release (lock);
748     else
749     {
750       wl_entry = lock_wl_find (lock, cl_entry);
751       GNUNET_assert (NULL != wl_entry);
752       lock_wl_remove (lock, wl_entry);
753     }
754   }
755   cl_remove_client (cl_entry);
756 }
757
758
759 /**
760  * Hashmap Iterator to delete lock entries in hash map
761  *
762  * @param cls NULL
763  * @param key current key code
764  * @param value value in the hash map
765  * @return GNUNET_YES if we should continue to
766  *         iterate,
767  *         GNUNET_NO if not.
768  */
769 static int
770 lock_delete_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
771 {
772   struct Lock *lock = value;
773
774   GNUNET_assert (NULL != lock);
775   while (NULL != lock->wl_head)
776   {
777     lock_wl_remove (lock, lock->wl_head);
778   }
779   GNUNET_assert (GNUNET_YES ==
780                  GNUNET_CONTAINER_multihashmap_remove (lock_map, key, lock));
781   GNUNET_free (lock->domain_name);
782   GNUNET_free (lock);
783   return GNUNET_YES;
784 }
785
786
787 /**
788  * Task to clean up and shutdown nicely
789  *
790  * @param cls NULL
791  * @param tc the TaskContext from scheduler
792  */
793 static void
794 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
795 {
796   LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down lock manager\n");
797   /* Clean the global ClientList */
798   while (NULL != cl_head)
799   {
800     while (NULL != cl_head->ll_head)    /* Clear the LockList */
801     {
802       cl_ll_remove_lock (cl_head, cl_head->ll_head);
803     }
804     cl_remove_client (cl_head);
805   }
806   /* Clean the global hash table */
807   GNUNET_CONTAINER_multihashmap_iterate (lock_map, &lock_delete_iterator, NULL);
808   GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (lock_map));
809   GNUNET_CONTAINER_multihashmap_destroy (lock_map);
810   lock_map = NULL;
811 }
812
813
814 /**
815  * Lock manager setup
816  *
817  * @param cls closure
818  * @param server the initialized server
819  * @param cfg configuration to use
820  */
821 static void
822 lockmanager_run (void *cls, struct GNUNET_SERVER_Handle *server,
823                  const struct GNUNET_CONFIGURATION_Handle *cfg)
824 {
825   static const struct GNUNET_SERVER_MessageHandler message_handlers[] = {
826     {&handle_acquire, NULL, GNUNET_MESSAGE_TYPE_LOCKMANAGER_ACQUIRE, 0},
827     {&handle_release, NULL, GNUNET_MESSAGE_TYPE_LOCKMANAGER_RELEASE, 0},
828     {NULL}
829   };
830   GNUNET_SERVER_add_handlers (server, message_handlers);
831   GNUNET_SERVER_disconnect_notify (server, &client_disconnect_cb, NULL);
832   lock_map = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_NO);
833   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
834                                 NULL);
835 }
836
837
838 /**
839  * The starting point of execution
840  */
841 int
842 main (int argc, char *const *argv)
843 {
844   return (GNUNET_OK ==
845           GNUNET_SERVICE_run (argc, argv, "lockmanager",
846                               GNUNET_SERVICE_OPTION_NONE, &lockmanager_run,
847                               NULL)) ? 0 : 1;
848 }
849
850 /* end of gnunet-service-lockmanager.c */