-renaming testing-new.h to testing.h, bumping library versions
[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 (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 static int
722 stop_lock_attempt (void *cls,
723                    const struct GNUNET_HashCode *key,
724                    void *value)
725 {
726   struct ClientList *cl_entry = cls;
727   struct Lock *lock = value;
728   struct WaitList *wl;
729   struct WaitList *next;
730
731   next = lock->wl_head;
732   while (NULL != (wl = next))
733   {
734     next = wl->next;
735     if (wl->cl_entry == cl_entry)
736     {
737       GNUNET_CONTAINER_DLL_remove (lock->wl_head,
738                                    lock->wl_tail,
739                                    wl);
740       GNUNET_free (wl);
741     }
742   }
743   return GNUNET_OK;
744 }
745
746
747 /**
748  * Callback for client disconnect
749  *
750  * @param cls NULL
751  * @param client the client which has disconnected
752  */
753 static void
754 client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
755 {
756   struct ClientList *cl_entry;
757   struct LockList *ll_entry;
758   struct Lock *lock;
759
760   if (NULL == client)
761     return;
762   LOG (GNUNET_ERROR_TYPE_DEBUG,
763        "A client has been disconnected -- freeing its locks and resources\n");
764   cl_entry = cl_find_client (client);
765   if (NULL == cl_entry)
766     return;
767   while (NULL != (ll_entry = cl_entry->ll_head))
768   {
769     lock = ll_entry->lock;
770     cl_ll_remove_lock (cl_entry, ll_entry);
771     process_lock_release (lock);
772   }
773   GNUNET_CONTAINER_multihashmap_iterate (lock_map,
774                                          &stop_lock_attempt,
775                                          cl_entry);
776   cl_remove_client (cl_entry);
777 }
778
779
780 /**
781  * Hashmap Iterator to delete lock entries in hash map
782  *
783  * @param cls NULL
784  * @param key current key code
785  * @param value value in the hash map
786  * @return GNUNET_YES if we should continue to
787  *         iterate,
788  *         GNUNET_NO if not.
789  */
790 static int
791 lock_delete_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
792 {
793   struct Lock *lock = value;
794
795   GNUNET_assert (NULL != lock);
796   while (NULL != lock->wl_head)
797   {
798     lock_wl_remove (lock, lock->wl_head);
799   }
800   GNUNET_assert (GNUNET_YES ==
801                  GNUNET_CONTAINER_multihashmap_remove (lock_map, key, lock));
802   GNUNET_free (lock->domain_name);
803   GNUNET_free (lock);
804   return GNUNET_YES;
805 }
806
807
808 /**
809  * Task to clean up and shutdown nicely
810  *
811  * @param cls NULL
812  * @param tc the TaskContext from scheduler
813  */
814 static void
815 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
816 {
817   LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down lock manager\n");
818   /* Clean the global ClientList */
819   while (NULL != cl_head)
820   {
821     while (NULL != cl_head->ll_head)    /* Clear the LockList */
822     {
823       cl_ll_remove_lock (cl_head, cl_head->ll_head);
824     }
825     cl_remove_client (cl_head);
826   }
827   /* Clean the global hash table */
828   GNUNET_CONTAINER_multihashmap_iterate (lock_map, &lock_delete_iterator, NULL);
829   GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (lock_map));
830   GNUNET_CONTAINER_multihashmap_destroy (lock_map);
831   lock_map = NULL;
832 }
833
834
835 /**
836  * Lock manager setup
837  *
838  * @param cls closure
839  * @param server the initialized server
840  * @param cfg configuration to use
841  */
842 static void
843 lockmanager_run (void *cls, struct GNUNET_SERVER_Handle *server,
844                  const struct GNUNET_CONFIGURATION_Handle *cfg)
845 {
846   static const struct GNUNET_SERVER_MessageHandler message_handlers[] = {
847     {&handle_acquire, NULL, GNUNET_MESSAGE_TYPE_LOCKMANAGER_ACQUIRE, 0},
848     {&handle_release, NULL, GNUNET_MESSAGE_TYPE_LOCKMANAGER_RELEASE, 0},
849     {NULL}
850   };
851   GNUNET_SERVER_add_handlers (server, message_handlers);
852   GNUNET_SERVER_disconnect_notify (server, &client_disconnect_cb, NULL);
853   lock_map = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_NO);
854   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
855                                 NULL);
856 }
857
858
859 /**
860  * The starting point of execution
861  */
862 int
863 main (int argc, char *const *argv)
864 {
865   return (GNUNET_OK ==
866           GNUNET_SERVICE_run (argc, argv, "lockmanager",
867                               GNUNET_SERVICE_OPTION_NONE, &lockmanager_run,
868                               NULL)) ? 0 : 1;
869 }
870
871 /* end of gnunet-service-lockmanager.c */