/*
- This file is part of GNUnet.
- (C) 2012 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 2, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
+ This file is part of GNUnet.
+ (C) 2012 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
*/
/**
#include "platform.h"
#include "gnunet_common.h"
+#include "gnunet_container_lib.h"
#include "gnunet_protocols.h"
#include "gnunet_service_lib.h"
#include "gnunet_server_lib.h"
#include "lockmanager.h"
-#define LOG(kind,...) \
- GNUNET_log_from (kind, "gnunet-service-lockmanager",__VA_ARGS__)
+
+#define LOG(kind,...) \
+ GNUNET_log (kind, __VA_ARGS__)
+
+#define TIME_REL_MINS(min) \
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, min)
+
+#define TIMEOUT TIME_REL_MINS(3)
+
+
+/**
+ * Doubly linked list of clients having connections to us
+ */
+struct ClientList;
+
+
+/**
+ * Doubly linked list of clients waiting for a lock
+ */
+struct WaitList
+{
+ /**
+ * The next client structure
+ */
+ struct WaitList *next;
+
+ /**
+ * The prev client structure
+ */
+ struct WaitList *prev;
+
+ /**
+ * Pointer to the client
+ */
+ struct ClientList *cl_entry;
+};
+
+
+/**
+ * Structure representing a Lock
+ */
+struct Lock
+{
+ /**
+ * List head of clients waiting for this lock
+ */
+ struct WaitList *wl_head;
+
+ /**
+ * List tail of clients waiting for this lock
+ */
+ struct WaitList *wl_tail;
+
+ /**
+ * The client which is currently holding this lock
+ */
+ struct ClientList *cl_entry;
+
+ /**
+ * The name of the locking domain this lock belongs to
+ */
+ char *domain_name;
+
+ /**
+ * The number of this lock
+ */
+ uint32_t lock_num;
+};
+
+
+/**
+ * A Lock element for a doubly linked list
+ */
+struct LockList
+{
+ /**
+ * The next element pointer
+ */
+ struct LockList *next;
+
+ /**
+ * Pointer to the previous element
+ */
+ struct LockList *prev;
+
+ /**
+ * Pointer to the Lock
+ */
+ struct Lock *lock;
+};
+
+
+/**
+ * Doubly linked list of clients having connections to us
+ */
+struct ClientList
+{
+
+ /**
+ * The next client structure
+ */
+ struct ClientList *next;
+
+ /**
+ * The previous client structure
+ */
+ struct ClientList *prev;
+
+ /**
+ * Head of the doubly linked list of the currently held locks by this client
+ */
+ struct LockList *ll_head;
+
+ /**
+ * Tail of the doubly linked list of the currently held locks by this client
+ */
+ struct LockList *ll_tail;
+
+ /**
+ * Pointer to the client
+ */
+ struct GNUNET_SERVER_Client *client;
+};
+
+
+/**
+ * Structure for matching a lock
+ */
+struct LockMatch
+{
+ /**
+ * The matched LockingRequest entry; Should be NULL if no entry is found
+ */
+ struct Lock *matched_entry;
+
+ /**
+ * The locking domain name of the lock
+ */
+ const char *domain_name;
+
+ /**
+ * The lock number
+ */
+ uint32_t lock_num;
+};
+
+
+/**
+ * Map of lock-keys to the 'struct LockList' entry for the key.
+ */
+static struct GNUNET_CONTAINER_MultiHashMap *lock_map;
+
+/**
+ * Head of the doubly linked list of clients currently connected
+ */
+static struct ClientList *cl_head;
+
+/**
+ * Tail of the doubly linked list of clients currently connected
+ */
+static struct ClientList *cl_tail;
+
+
+/**
+ * Get the key for the given lock in the 'lock_map'.
+ *
+ * @param domain_name
+ * @param lock_number
+ * @param key set to the key
+ */
+static void
+get_key (const char *domain_name, uint32_t lock_number,
+ struct GNUNET_HashCode *key)
+{
+ uint32_t *last_32;
+
+ GNUNET_CRYPTO_hash (domain_name, strlen (domain_name), key);
+ last_32 = (uint32_t *) key;
+ *last_32 ^= lock_number;
+}
+
+
+/**
+ * Hashmap iterator for matching a lock
+ *
+ * @param cls the LockMatch structure
+ * @param key current key code
+ * @param value value in the hash map (struct Lock)
+ * @return GNUNET_YES if we should continue to
+ * iterate,
+ * GNUNET_NO if not.
+ */
+static int
+match_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
+{
+ struct LockMatch *match = cls;
+ struct Lock *lock = value;
+
+ if ((match->lock_num == lock->lock_num) &&
+ (0 == strcmp (match->domain_name, lock->domain_name)))
+ {
+ match->matched_entry = lock;
+ return GNUNET_NO;
+ }
+ return GNUNET_YES;
+}
+
+
+/**
+ * Function to search for a lock in the global lock hashmap
+ *
+ * @param domain_name the name of the locking domain
+ * @param lock_num the number of the lock
+ * @return the lock if found; NULL if not
+ */
+static struct Lock *
+find_lock (const char *domain_name, const uint32_t lock_num)
+{
+ struct LockMatch match;
+ struct GNUNET_HashCode key;
+
+ match.lock_num = lock_num;
+ match.domain_name = domain_name;
+ match.matched_entry = NULL;
+ get_key (domain_name, lock_num, &key);
+ GNUNET_CONTAINER_multihashmap_get_multiple (lock_map, &key, &match_iterator,
+ &match);
+ return match.matched_entry;
+}
+
+
+/**
+ * Adds a lock to the global lock hashmap
+ *
+ * @param domain_name the name of the lock's locking domain
+ * @param lock_num the lock number
+ * @return pointer to the lock structure which is added to lock map
+ */
+static struct Lock *
+add_lock (const char *domain_name, uint32_t lock_num)
+{
+ struct Lock *lock;
+ struct GNUNET_HashCode key;
+ size_t domain_name_len;
+
+ lock = GNUNET_malloc (sizeof (struct Lock));
+ domain_name_len = strlen (domain_name) + 1;
+ lock->domain_name = GNUNET_malloc (domain_name_len);
+ strncpy (lock->domain_name, domain_name, domain_name_len);
+ lock->lock_num = lock_num;
+ get_key (domain_name, lock_num, &key);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Adding a lock with num: %d and domain: %s to the lock map\n",
+ lock->lock_num, lock->domain_name);
+ GNUNET_CONTAINER_multihashmap_put (lock_map, &key, lock,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+ return lock;
+}
+
+
+/**
+ * Removes a lock from the lock map. The WaitList of the lock should be empty
+ *
+ * @param lock the lock to remove
+ */
+static void
+remove_lock (struct Lock *lock)
+{
+ struct GNUNET_HashCode key;
+
+ GNUNET_assert (NULL == lock->wl_head);
+ get_key (lock->domain_name, lock->lock_num, &key);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Removing lock with num: %u, domain: %s from lock map\n", lock->lock_num,
+ lock->domain_name);
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (lock_map, &key, lock));
+ GNUNET_free (lock->domain_name);
+ GNUNET_free (lock);
+}
+
+
+/**
+ * Find the LockList entry corresponding to the given Lock in a ClientList
+ * entry
+ *
+ * @param cl_entry the ClientList entry whose lock list has to be searched
+ * @param lock the lock which has to be matched
+ * @return the matching LockList entry; NULL if no match is found
+ */
+static struct LockList *
+cl_ll_find_lock (struct ClientList *cl_entry, const struct Lock *lock)
+{
+ struct LockList *ll_entry;
+
+ for (ll_entry = cl_entry->ll_head; NULL != ll_entry;
+ ll_entry = ll_entry->next)
+ {
+ if (lock == ll_entry->lock)
+ return ll_entry;
+ }
+ return NULL;
+}
+
+
+/**
+ * Function to append a lock to the lock list of a ClientList entry
+ *
+ * @param cl_entry the client which currently owns this lock
+ * @param lock the lock to be added to the cl_entry's lock list
+ */
+static void
+cl_ll_add_lock (struct ClientList *cl_entry, struct Lock *lock)
+{
+ struct LockList *ll_entry;
+
+ ll_entry = GNUNET_malloc (sizeof (struct LockList));
+ ll_entry->lock = lock;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Adding a lock with num: %u and domain: %s to lock list\n",
+ lock->lock_num, lock->domain_name);
+ GNUNET_CONTAINER_DLL_insert_tail (cl_entry->ll_head, cl_entry->ll_tail,
+ ll_entry);
+}
+
+
+/**
+ * Function to delete a lock from the lock list of the given ClientList entry
+ *
+ * @param cl_entry the ClientList entry
+ * @param ll_entry the LockList entry to be deleted
+ */
+static void
+cl_ll_remove_lock (struct ClientList *cl_entry, struct LockList *ll_entry)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Removing lock with num: %u, domain: %s from lock list of a client\n",
+ ll_entry->lock->lock_num, ll_entry->lock->domain_name);
+ GNUNET_assert (NULL != cl_entry->ll_head);
+ GNUNET_CONTAINER_DLL_remove (cl_entry->ll_head, cl_entry->ll_tail, ll_entry);
+ GNUNET_free (ll_entry);
+}
+
+
+/**
+ * Find a WaitList entry in the waiting list of a lock
+ *
+ * @param lock the lock whose wait list has to be searched
+ * @param cl_entry the ClientList entry to be searched
+ * @return the WaitList entry matching the given cl_entry; NULL if not match
+ * was found
+ */
+static struct WaitList *
+lock_wl_find (const struct Lock *lock, const struct ClientList *cl_entry)
+{
+ struct WaitList *wl_entry;
+
+ for (wl_entry = lock->wl_head; NULL != wl_entry; wl_entry = wl_entry->next)
+ {
+ if (cl_entry == wl_entry->cl_entry)
+ return wl_entry;
+ }
+ return NULL;
+}
+
+
+/**
+ * Add a client to the wait list of given lock
+ *
+ * @param lock the lock list entry of a lock
+ * @param cl_entry the client to queue for the lock's wait list
+ */
+static void
+lock_wl_add_client (struct Lock *lock, struct ClientList *cl_entry)
+{
+ struct WaitList *wl_entry;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Adding a client to lock's wait list (lock num: %u, domain: %s)\n",
+ lock->lock_num, lock->domain_name);
+ wl_entry = GNUNET_malloc (sizeof (struct WaitList));
+ wl_entry->cl_entry = cl_entry;
+ GNUNET_CONTAINER_DLL_insert_tail (lock->wl_head, lock->wl_tail, wl_entry);
+}
+
+
+/**
+ * Remove an entry from the wait list of the given lock
+ *
+ * @param lock the lock
+ * @param wl_entry the wait list entry to be removed
+ */
+static void
+lock_wl_remove (struct Lock *lock, struct WaitList *wl_entry)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Removing client from wait list of lock with num: %u, domain: %s\n",
+ lock->lock_num, lock->domain_name);
+ GNUNET_CONTAINER_DLL_remove (lock->wl_head, lock->wl_tail, wl_entry);
+ GNUNET_free (wl_entry);
+}
+
+
+/**
+ * Search for a client in the client list
+ *
+ * @param client the client to be searched for
+ * @return the ClientList entry; NULL if the client is not found
+ */
+static struct ClientList *
+cl_find_client (const struct GNUNET_SERVER_Client *client)
+{
+ struct ClientList *current;
+
+ for (current = cl_head; NULL != current; current = current->next)
+ if (client == current->client)
+ return current;
+ return NULL;
+}
+
+
+/**
+ * Append a client to the client list
+ *
+ * @param client the client to be appended to the list
+ * @return the client list entry which is added to the client list
+ */
+static struct ClientList *
+cl_add_client (struct GNUNET_SERVER_Client *client)
+{
+ struct ClientList *new_client;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding a client to the client list\n");
+ new_client = GNUNET_malloc (sizeof (struct ClientList));
+ GNUNET_SERVER_client_keep (client);
+ new_client->client = client;
+ GNUNET_CONTAINER_DLL_insert_tail (cl_head, cl_tail, new_client);
+ return new_client;
+}
+
+
+/**
+ * Delete the given client from the client list. The LockList should be empty
+ *
+ * @param cl_entry the client list entry to delete
+ */
+static void
+cl_remove_client (struct ClientList *cl_entry)
+{
+ GNUNET_assert (NULL == cl_entry->ll_head);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Removing a client from the client list\n");
+ GNUNET_SERVER_client_drop (cl_entry->client);
+ GNUNET_CONTAINER_DLL_remove (cl_head, cl_tail, cl_entry);
+ GNUNET_free (cl_entry);
+}
+
+
+/**
+ * Transmit notify for sending message to client
+ *
+ * @param cls the message to send
+ * @param size number of bytes available in buf
+ * @param buf where the callee should write the message
+ * @return number of bytes written to buf
+ */
+static size_t
+transmit_notify (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_LOCKMANAGER_Message *msg = cls;
+ uint16_t msg_size;
+
+ if ((0 == size) || (NULL == buf))
+ {
+ /* FIXME: Timed out -- requeue? */
+ return 0;
+ }
+ msg_size = ntohs (msg->header.size);
+ GNUNET_assert (size >= msg_size);
+ memcpy (buf, msg, msg_size);
+ GNUNET_free (msg);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Message of size %u sent\n", msg_size);
+ return msg_size;
+}
+
+
+/**
+ * Send SUCCESS message to the client
+ *
+ * @param client the client to which the message has to be sent
+ * @param domain_name the locking domain of the successfully acquried lock
+ * @param lock_num the number of the successfully acquired lock
+ */
+static void
+send_success_msg (struct GNUNET_SERVER_Client *client, const char *domain_name,
+ int lock_num)
+{
+ struct GNUNET_LOCKMANAGER_Message *reply;
+ size_t domain_name_len;
+ uint16_t reply_size;
+
+ domain_name_len = strlen (domain_name) + 1;
+ reply_size = sizeof (struct GNUNET_LOCKMANAGER_Message) + domain_name_len;
+ reply = GNUNET_malloc (reply_size);
+ reply->header.size = htons (reply_size);
+ reply->header.type = htons (GNUNET_MESSAGE_TYPE_LOCKMANAGER_SUCCESS);
+ reply->lock = htonl (lock_num);
+ strncpy ((char *) &reply[1], domain_name, domain_name_len);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending SUCCESS message for lock with num: %u, domain: %s\n", lock_num,
+ domain_name);
+ GNUNET_SERVER_notify_transmit_ready (client, reply_size, TIMEOUT,
+ &transmit_notify, reply);
+}
/**
* Handler for GNUNET_MESSAGE_TYPE_LOCKMANAGER_ACQUIRE
*
- * @param
- * @return
+ * @param cls NULL
+ * @param client the client sending this message
+ * @param message GNUNET_MESSAGE_TYPE_LOCKMANAGER_ACQUIRE message
*/
static void
-handle_acquire (void *cls,
- struct GNUNET_SERVER_Client *client,
+handle_acquire (void *cls, struct GNUNET_SERVER_Client *client,
const struct GNUNET_MessageHeader *message)
{
- // const struct GNUNET_LOCKMANAGER_Message *msg = message;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Received a ACQUIRE message\n");
+ const struct GNUNET_LOCKMANAGER_Message *request;
+ const char *domain_name;
+ struct Lock *lock;
+ struct ClientList *cl_entry;
+ uint32_t lock_num;
+ uint16_t msize;
+ msize = htons (message->size);
+ if (msize <= sizeof (struct GNUNET_LOCKMANAGER_Message))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ request = (struct GNUNET_LOCKMANAGER_Message *) message;
+ domain_name = (const char *) &request[1];
+ msize -= sizeof (struct GNUNET_LOCKMANAGER_Message);
+ if ('\0' != domain_name[msize - 1])
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Bad domain `%.*s' - byte with index %u is %X, not 0.\n", msize,
+ domain_name, msize - 1, (unsigned int) domain_name[msize - 1]);
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ lock_num = ntohl (request->lock);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Received an ACQUIRE message for lock num: %u domain: %s\n", lock_num,
+ domain_name);
+ if (NULL == (cl_entry = cl_find_client (client)))
+ cl_entry = cl_add_client (client); /* Add client if not in client list */
+ if (NULL != (lock = find_lock (domain_name, lock_num)))
+ {
+ if (lock->cl_entry == cl_entry)
+ { /* Client is requesting a lock it already owns */
+ GNUNET_break_op (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ lock_wl_add_client (lock, cl_entry);
+ cl_ll_add_lock (cl_entry, lock);
+ }
+ else /* Lock not present */
+ {
+ lock = add_lock (domain_name, lock_num);
+ lock->cl_entry = cl_entry;
+ cl_ll_add_lock (cl_entry, lock);
+ send_success_msg (cl_entry->client, domain_name, lock_num);
+ }
GNUNET_SERVER_receive_done (client, GNUNET_OK);
}
+/**
+ * This function gives the lock to the first client in the wait list of the
+ * lock. If no clients are currently waiting for this lock, the lock is then
+ * destroyed.
+ *
+ * @param lock the lock which has to be processed for release
+ */
+static void
+process_lock_release (struct Lock *lock)
+{
+ struct WaitList *wl_entry;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Processing lock release for lock with num: %u, domain: %s\n",
+ lock->lock_num, lock->domain_name);
+ wl_entry = lock->wl_head;
+ if (NULL == wl_entry)
+ {
+ remove_lock (lock); /* No clients waiting for this lock - delete */
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Giving lock to a client from wait list\n");
+ lock->cl_entry = wl_entry->cl_entry;
+ lock_wl_remove (lock, wl_entry);
+ send_success_msg (lock->cl_entry->client, lock->domain_name, lock->lock_num);
+}
+
+
/**
* Handle for GNUNET_MESSAGE_TYPE_LOCKMANAGER_RELEASE
*
- * @param
- * @return
+ * @param cls NULL
+ * @param client the client sending this message
+ * @param message the LOCKMANAGER_RELEASE message
*/
static void
-handle_release (void *cls,
- struct GNUNET_SERVER_Client *client,
+handle_release (void *cls, struct GNUNET_SERVER_Client *client,
const struct GNUNET_MessageHeader *message)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Received a RELEASE message\n");
+ const struct GNUNET_LOCKMANAGER_Message *request;
+ struct ClientList *cl_entry;
+ struct WaitList *wl_entry;
+ struct LockList *ll_entry;
+ const char *domain_name;
+ struct Lock *lock;
+ uint32_t lock_num;
+ uint16_t msize;
+
+ msize = ntohs (message->size);
+ if (msize <= sizeof (struct GNUNET_LOCKMANAGER_Message))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ request = (const struct GNUNET_LOCKMANAGER_Message *) message;
+ domain_name = (const char *) &request[1];
+ msize -= sizeof (struct GNUNET_LOCKMANAGER_Message);
+ if ('\0' != domain_name[msize - 1])
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+
+ }
+ lock_num = ntohl (request->lock);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Received RELEASE message for lock with num: %d, domain: %s\n", lock_num,
+ domain_name);
+ if (NULL == (cl_entry = cl_find_client (client)))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ lock = find_lock (domain_name, lock_num);
+ if (NULL == lock)
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ if (NULL == (ll_entry = cl_ll_find_lock (cl_entry, lock)))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ cl_ll_remove_lock (cl_entry, ll_entry);
+ if (cl_entry == lock->cl_entry)
+ {
+ process_lock_release (lock);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ /* remove 'client' from wait list (check that it is not there...) */
+ if (NULL != (wl_entry = lock_wl_find (lock, cl_entry)))
+ {
+ lock_wl_remove (lock, wl_entry);
+ }
GNUNET_SERVER_receive_done (client, GNUNET_OK);
}
+/**
+ * Callback for client disconnect
+ *
+ * @param cls NULL
+ * @param client the client which has disconnected
+ */
+static void
+client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
+{
+ struct ClientList *cl_entry;
+ struct LockList *ll_entry;
+ struct Lock *lock;
+ struct WaitList *wl_entry;
+
+ if (NULL == client)
+ return;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "A client has been disconnected -- freeing its locks and resources\n");
+ cl_entry = cl_find_client (client);
+ if (NULL == cl_entry)
+ return;
+ while (NULL != (ll_entry = cl_entry->ll_head))
+ {
+ lock = ll_entry->lock;
+ cl_ll_remove_lock (cl_entry, ll_entry);
+ if (lock->cl_entry == cl_entry)
+ process_lock_release (lock);
+ else
+ {
+ wl_entry = lock_wl_find (lock, cl_entry);
+ GNUNET_assert (NULL != wl_entry);
+ lock_wl_remove (lock, wl_entry);
+ }
+ }
+ cl_remove_client (cl_entry);
+}
+
+
+/**
+ * Hashmap Iterator to delete lock entries in hash map
+ *
+ * @param cls NULL
+ * @param key current key code
+ * @param value value in the hash map
+ * @return GNUNET_YES if we should continue to
+ * iterate,
+ * GNUNET_NO if not.
+ */
+static int
+lock_delete_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
+{
+ struct Lock *lock = value;
+
+ GNUNET_assert (NULL != lock);
+ while (NULL != lock->wl_head)
+ {
+ lock_wl_remove (lock, lock->wl_head);
+ }
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (lock_map, key, lock));
+ GNUNET_free (lock->domain_name);
+ GNUNET_free (lock);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Task to clean up and shutdown nicely
+ *
+ * @param cls NULL
+ * @param tc the TaskContext from scheduler
+ */
+static void
+shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down lock manager\n");
+ /* Clean the global ClientList */
+ while (NULL != cl_head)
+ {
+ while (NULL != cl_head->ll_head) /* Clear the LockList */
+ {
+ cl_ll_remove_lock (cl_head, cl_head->ll_head);
+ }
+ cl_remove_client (cl_head);
+ }
+ /* Clean the global hash table */
+ GNUNET_CONTAINER_multihashmap_iterate (lock_map, &lock_delete_iterator, NULL);
+ GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (lock_map));
+ GNUNET_CONTAINER_multihashmap_destroy (lock_map);
+ lock_map = NULL;
+}
+
+
/**
* Lock manager setup
*
* @param server the initialized server
* @param cfg configuration to use
*/
-static void
-lockmanager_run (void *cls,
- struct GNUNET_SERVER_Handle * server,
+static void
+lockmanager_run (void *cls, struct GNUNET_SERVER_Handle *server,
const struct GNUNET_CONFIGURATION_Handle *cfg)
{
- struct GNUNET_SERVER_MessageHandler message_handlers[] =
- {
- {&handle_acquire, NULL, GNUNET_MESSAGE_TYPE_LOCKMANAGER_ACQUIRE, 0},
- {&handle_release, NULL, GNUNET_MESSAGE_TYPE_LOCKMANAGER_RELEASE, 0},
- {NULL}
- };
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting lockmanager\n");
- GNUNET_SERVER_add_handlers (server,
- message_handlers);
-
+ static const struct GNUNET_SERVER_MessageHandler message_handlers[] = {
+ {&handle_acquire, NULL, GNUNET_MESSAGE_TYPE_LOCKMANAGER_ACQUIRE, 0},
+ {&handle_release, NULL, GNUNET_MESSAGE_TYPE_LOCKMANAGER_RELEASE, 0},
+ {NULL}
+ };
+ GNUNET_SERVER_add_handlers (server, message_handlers);
+ GNUNET_SERVER_disconnect_notify (server, &client_disconnect_cb, NULL);
+ lock_map = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_NO);
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
+ NULL);
}
+
/**
* The starting point of execution
*/
-int main (int argc, char *const *argv)
+int
+main (int argc, char *const *argv)
{
- int ret;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "main()\n");
- ret =
- (GNUNET_OK ==
- GNUNET_SERVICE_run (argc,
- argv,
- "lockmanager",
- GNUNET_SERVICE_OPTION_NONE,
- &lockmanager_run,
- NULL)) ? 0 : 1;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "main() END\n");
- return ret;
+ return (GNUNET_OK ==
+ GNUNET_SERVICE_run (argc, argv, "lockmanager",
+ GNUNET_SERVICE_OPTION_NONE, &lockmanager_run,
+ NULL)) ? 0 : 1;
}
+
+/* end of gnunet-service-lockmanager.c */