added work ssh key
[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])
580   {
581     GNUNET_break (0);
582     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
583     return;
584   }
585   lock_num = ntohl (request->lock);
586   LOG (GNUNET_ERROR_TYPE_DEBUG,
587        "Received an ACQUIRE message for lock num: %u domain: %s\n", lock_num,
588        domain_name);
589   if (NULL == (cl_entry = cl_find_client (client)))
590     cl_entry = cl_add_client (client);  /* Add client if not in client list */
591   if (NULL != (lock = find_lock (domain_name, lock_num)))
592   {
593     if (lock->cl_entry == cl_entry)
594     {                           /* Client is requesting a lock it already owns */
595       GNUNET_break (0);
596       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
597       return;
598     }
599     lock_wl_add_client (lock, cl_entry);
600     cl_ll_add_lock (cl_entry, lock);
601   }
602   else                          /* Lock not present */
603   {
604     lock = add_lock (domain_name, lock_num);
605     lock->cl_entry = cl_entry;
606     cl_ll_add_lock (cl_entry, lock);
607     send_success_msg (cl_entry->client, domain_name, lock_num);
608   }
609   GNUNET_SERVER_receive_done (client, GNUNET_OK);
610 }
611
612
613 /**
614  * This function gives the lock to the first client in the wait list of the
615  * lock. If no clients are currently waiting for this lock, the lock is then
616  * destroyed.
617  *
618  * @param lock the lock which has to be processed for release
619  */
620 static void
621 process_lock_release (struct Lock *lock)
622 {
623   struct WaitList *wl_entry;
624
625   LOG (GNUNET_ERROR_TYPE_DEBUG,
626        "Processing lock release for lock with num: %u, domain: %s\n",
627        lock->lock_num, lock->domain_name);
628   wl_entry = lock->wl_head;
629   if (NULL == wl_entry)
630   {
631     remove_lock (lock);         /* No clients waiting for this lock - delete */
632     return;
633   }
634   LOG (GNUNET_ERROR_TYPE_DEBUG, "Giving lock to a client from wait list\n");
635   lock->cl_entry = wl_entry->cl_entry;
636   lock_wl_remove (lock, wl_entry);
637   send_success_msg (lock->cl_entry->client, lock->domain_name, lock->lock_num);
638   return;
639 }
640
641
642 /**
643  * Handle for GNUNET_MESSAGE_TYPE_LOCKMANAGER_RELEASE
644  *
645  * @param cls NULL
646  * @param client the client sending this message
647  * @param message the LOCKMANAGER_RELEASE message
648  */
649 static void
650 handle_release (void *cls, struct GNUNET_SERVER_Client *client,
651                 const struct GNUNET_MessageHeader *message)
652 {
653   const struct GNUNET_LOCKMANAGER_Message *request;
654   struct ClientList *cl_entry;
655   struct WaitList *wl_entry;
656   struct LockList *ll_entry;
657   const char *domain_name;
658   struct Lock *lock;
659   uint32_t lock_num;
660   uint16_t msize;
661
662   msize = ntohs (message->size);
663   if (msize <= sizeof (struct GNUNET_LOCKMANAGER_Message))
664   {
665     GNUNET_break (0);
666     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
667     return;
668   }
669   request = (const struct GNUNET_LOCKMANAGER_Message *) message;
670   domain_name = (const char *) &request[1];
671   msize -= sizeof (struct GNUNET_LOCKMANAGER_Message);
672   if ('\0' != domain_name[msize - 1])
673   {
674     GNUNET_break (0);
675     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
676     return;
677
678
679   }
680   lock_num = ntohl (request->lock);
681   LOG (GNUNET_ERROR_TYPE_DEBUG,
682        "Received RELEASE message for lock with num: %d, domain: %s\n", lock_num,
683        domain_name);
684   if (NULL == (cl_entry = cl_find_client (client)))
685   {
686     GNUNET_break (0);
687     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
688     return;
689   }
690   lock = find_lock (domain_name, lock_num);
691   if (NULL == lock)
692   {
693     GNUNET_break (0);
694     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
695     return;
696   }
697   if (NULL == (ll_entry = cl_ll_find_lock (cl_entry, lock)))
698   {
699     GNUNET_break (0);
700     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
701     return;
702   }
703   cl_ll_remove_lock (cl_entry, ll_entry);
704   if (cl_entry == lock->cl_entry)
705   {
706     process_lock_release (lock);
707     GNUNET_SERVER_receive_done (client, GNUNET_OK);
708     return;
709   }
710   /* remove 'client' from wait list (check that it is not there...) */
711   if (NULL != (wl_entry = lock_wl_find (lock, cl_entry)))
712   {
713     lock_wl_remove (lock, wl_entry);
714   }
715   GNUNET_SERVER_receive_done (client, GNUNET_OK);
716 }
717
718
719 /**
720  * Callback for client disconnect
721  *
722  * @param cls NULL
723  * @param client the client which has disconnected
724  */
725 static void
726 client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
727 {
728   struct ClientList *cl_entry;
729   struct LockList *ll_entry;
730   struct Lock *lock;
731
732   if (NULL == client)
733     return;
734   LOG (GNUNET_ERROR_TYPE_DEBUG,
735        "A client has been disconnected -- freeing its locks and resources\n");
736   cl_entry = cl_find_client (client);
737   if (NULL == cl_entry)
738     return;
739   while (NULL != (ll_entry = cl_entry->ll_head))
740   {
741     lock = ll_entry->lock;
742     cl_ll_remove_lock (cl_entry, ll_entry);
743     process_lock_release (lock);
744   }
745   cl_remove_client (cl_entry);
746 }
747
748
749 /**
750  * Hashmap Iterator to delete lock entries in hash map
751  *
752  * @param cls NULL
753  * @param key current key code
754  * @param value value in the hash map
755  * @return GNUNET_YES if we should continue to
756  *         iterate,
757  *         GNUNET_NO if not.
758  */
759 static int
760 lock_delete_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
761 {
762   struct Lock *lock = value;
763
764   GNUNET_assert (NULL != lock);
765   while (NULL != lock->wl_head)
766   {
767     lock_wl_remove (lock, lock->wl_head);
768   }
769   GNUNET_assert (GNUNET_YES ==
770                  GNUNET_CONTAINER_multihashmap_remove (lock_map, key, lock));
771   GNUNET_free (lock->domain_name);
772   GNUNET_free (lock);
773   return GNUNET_YES;
774 }
775
776
777 /**
778  * Task to clean up and shutdown nicely
779  *
780  * @param cls NULL
781  * @param tc the TaskContext from scheduler
782  */
783 static void
784 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
785 {
786   LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down lock manager\n");
787   /* Clean the global ClientList */
788   while (NULL != cl_head)
789   {
790     while (NULL != cl_head->ll_head)    /* Clear the LockList */
791     {
792       cl_ll_remove_lock (cl_head, cl_head->ll_head);
793     }
794     cl_remove_client (cl_head);
795   }
796   /* Clean the global hash table */
797   GNUNET_CONTAINER_multihashmap_iterate (lock_map, &lock_delete_iterator, NULL);
798   GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (lock_map));
799   GNUNET_CONTAINER_multihashmap_destroy (lock_map);
800 }
801
802
803 /**
804  * Lock manager setup
805  *
806  * @param cls closure
807  * @param server the initialized server
808  * @param cfg configuration to use
809  */
810 static void
811 lockmanager_run (void *cls, struct GNUNET_SERVER_Handle *server,
812                  const struct GNUNET_CONFIGURATION_Handle *cfg)
813 {
814   static const struct GNUNET_SERVER_MessageHandler message_handlers[] = {
815     {&handle_acquire, NULL, GNUNET_MESSAGE_TYPE_LOCKMANAGER_ACQUIRE, 0},
816     {&handle_release, NULL, GNUNET_MESSAGE_TYPE_LOCKMANAGER_RELEASE, 0},
817     {NULL}
818   };
819   GNUNET_SERVER_add_handlers (server, message_handlers);
820   GNUNET_SERVER_disconnect_notify (server, &client_disconnect_cb, NULL);
821   lock_map = GNUNET_CONTAINER_multihashmap_create (30);
822   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
823                                 NULL);
824 }
825
826
827 /**
828  * The starting point of execution
829  */
830 int
831 main (int argc, char *const *argv)
832 {
833   return (GNUNET_OK ==
834           GNUNET_SERVICE_run (argc, argv, "lockmanager",
835                               GNUNET_SERVICE_OPTION_NONE, &lockmanager_run,
836                               NULL)) ? 0 : 1;
837 }
838
839 /* end of gnunet-service-lockmanager.c */