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