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