* The next client structure
*/
struct WaitList *next;
-
+
/**
* The prev client structure
*/
};
+/**
+ * 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.
*/
* @param key set to the key
*/
static void
-get_key (const char *domain_name,
- uint32_t lock_number,
- struct GNUNET_HashCode *key)
+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);
+ 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
*
* @return the lock if found; NULL if not
*/
static struct Lock *
-find_lock (const char *domain_name,
- const uint32_t lock_num)
-
+find_lock (const char *domain_name, const uint32_t lock_num)
{
- struct Lock *matched_lock;
+ struct LockMatch match;
struct GNUNET_HashCode key;
- matched_lock = NULL;
- int match_lock (void *cls,
- const GNUNET_HashCode *key,
- void *value)
- {
- matched_lock = value;
-
- if ((lock_num == matched_lock->lock_num)
- && (0 == strcmp (domain_name, matched_lock->domain_name)))
- return GNUNET_NO;
- matched_lock = NULL;
- return GNUNET_YES;
- }
+ 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_lock,
- NULL);
- return matched_lock;
+ GNUNET_CONTAINER_multihashmap_get_multiple (lock_map, &key, &match_iterator,
+ &match);
+ return match.matched_entry;
}
* @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)
+add_lock (const char *domain_name, uint32_t lock_num)
{
struct Lock *lock;
struct GNUNET_HashCode 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_multihashmap_put (lock_map, &key, lock,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
return lock;
}
/**
- * Removes a lock from the lock map
+ * Removes a lock from the lock map. The WaitList of the lock should be empty
*
- * @param the lock to remove
+ * @param lock the lock to remove
*/
static void
remove_lock (struct Lock *lock)
{
struct GNUNET_HashCode key;
- get_key (lock->domain_name,
- lock->lock_num,
- &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));
+ "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);
}
* @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)
+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)
+ for (ll_entry = cl_entry->ll_head; NULL != ll_entry;
+ ll_entry = ll_entry->next)
{
if (lock == ll_entry->lock)
return ll_entry;
* @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)
+cl_ll_add_lock (struct ClientList *cl_entry, struct Lock *lock)
{
struct LockList *ll_entry;
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,
+ GNUNET_CONTAINER_DLL_insert_tail (cl_entry->ll_head, cl_entry->ll_tail,
ll_entry);
}
* @param ll_entry the LockList entry to be deleted
*/
static void
-cl_ll_remove_lock (struct ClientList *cl_entry,
- struct LockList *ll_entry)
+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);
+ 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_CONTAINER_DLL_remove (cl_entry->ll_head, cl_entry->ll_tail, ll_entry);
GNUNET_free (ll_entry);
}
* was found
*/
static struct WaitList *
-lock_wl_find (const struct Lock *lock,
- const struct ClientList *cl_entry)
+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)
+ for (wl_entry = lock->wl_head; NULL != wl_entry; wl_entry = wl_entry->next)
{
if (cl_entry == wl_entry->cl_entry)
return wl_entry;
* @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)
+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);
+ 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);
+ GNUNET_CONTAINER_DLL_insert_tail (lock->wl_head, lock->wl_tail, wl_entry);
}
* @param wl_entry the wait list entry to be removed
*/
static void
-lock_wl_remove (struct Lock *lock,
- struct WaitList *wl_entry)
+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_CONTAINER_DLL_remove (lock->wl_head, lock->wl_tail, wl_entry);
GNUNET_free (wl_entry);
}
* @return the ClientList entry; NULL if the client is not found
*/
static struct ClientList *
-cl_find_client (const struct GNUNET_SERVER_Client *client)
+cl_find_client (const struct GNUNET_SERVER_Client *client)
{
struct ClientList *current;
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");
+
+ 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);
+ GNUNET_CONTAINER_DLL_insert_tail (cl_head, cl_tail, new_client);
return new_client;
}
/**
- * Delete the given client from the client list
+ * 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)
{
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Removing a client from the client list\n");
+ 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_CONTAINER_DLL_remove (cl_head, cl_tail, cl_entry);
GNUNET_free (cl_entry);
}
* @param buf where the callee should write the message
* @return number of bytes written to buf
*/
-static size_t
+static size_t
transmit_notify (void *cls, size_t size, void *buf)
{
struct GNUNET_LOCKMANAGER_Message *msg = cls;
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);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Message of size %u sent\n", msg_size);
return msg_size;
}
* @param lock_num the number of the successfully acquired lock
*/
static void
-send_success_msg (struct GNUNET_SERVER_Client *client,
- const char *domain_name,
+send_success_msg (struct GNUNET_SERVER_Client *client, const char *domain_name,
int lock_num)
{
struct GNUNET_LOCKMANAGER_Message *reply;
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);
+ "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);
}
* @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 *request;
request = (struct GNUNET_LOCKMANAGER_Message *) message;
domain_name = (const char *) &request[1];
msize -= sizeof (struct GNUNET_LOCKMANAGER_Message);
- if ('\0' != domain_name[msize])
+ 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)))
+ "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 (0);
+ { /* Client is requesting a lock it already owns */
+ GNUNET_break_op (0);
GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
return;
}
wl_entry = lock->wl_head;
if (NULL == wl_entry)
{
- remove_lock (lock); /* No clients waiting for this lock - delete */
+ 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");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Giving lock to a client from wait list\n");
lock->cl_entry = wl_entry->cl_entry;
- cl_ll_add_lock (wl_entry->cl_entry, lock);
- lock_wl_remove(lock, wl_entry);
- send_success_msg (lock->cl_entry->client,
- lock->domain_name,
- lock->lock_num);
- return;
+ lock_wl_remove (lock, wl_entry);
+ send_success_msg (lock->cl_entry->client, lock->domain_name, lock->lock_num);
}
* @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)
{
const struct GNUNET_LOCKMANAGER_Message *request;
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])
+ 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);
+ "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_break (0);
GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
return;
}
lock = find_lock (domain_name, lock_num);
- if(NULL == lock)
- {
+ if (NULL == lock)
+ {
GNUNET_break (0);
GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
return;
{
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");
+ "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))
{
- process_lock_release (ll_entry->lock);
+ 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)
{
- 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 (30);
+ 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)
{
- return
- (GNUNET_OK ==
- GNUNET_SERVICE_run (argc,
- argv,
- "lockmanager",
- GNUNET_SERVICE_OPTION_NONE,
- &lockmanager_run,
- NULL)) ? 0 : 1;
+ return (GNUNET_OK ==
+ GNUNET_SERVICE_run (argc, argv, "lockmanager",
+ GNUNET_SERVICE_OPTION_NONE, &lockmanager_run,
+ NULL)) ? 0 : 1;
}
+
+/* end of gnunet-service-lockmanager.c */