2 This file is part of GNUnet.
3 (C) 2012 Christian Grothoff (and other contributing authors)
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.
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.
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.
22 * @file lockmanager/lockmanager_api.c
23 * @brief API implementation of gnunet_lockmanager_service.h
24 * @author Sree Harsha Totakura
28 #include "gnunet_common.h"
29 #include "gnunet_container_lib.h"
30 #include "gnunet_client_lib.h"
31 #include "gnunet_crypto_lib.h"
32 #include "gnunet_lockmanager_service.h"
33 #include "gnunet_protocols.h"
35 #include "lockmanager.h"
37 #define LOG(kind,...) \
38 GNUNET_log_from (kind, "lockmanager-api",__VA_ARGS__)
40 #define TIME_REL_MINS(min) \
41 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, min)
43 #define TIMEOUT TIME_REL_MINS(3)
46 * Handler for the lockmanager service
48 struct GNUNET_LOCKMANAGER_Handle
51 * The client connection to the service
53 struct GNUNET_CLIENT_Connection *conn;
58 struct GNUNET_CONTAINER_MultiHashMap *hashmap;
63 * Structure for Locking Request
65 struct GNUNET_LOCKMANAGER_LockingRequest
68 * The handle associated with this request
70 struct GNUNET_LOCKMANAGER_Handle *handle;
75 GNUNET_LOCKMANAGER_StatusCallback status_cb;
78 * Closure for the status callback
83 * The pending transmit handle for the ACQUIRE message
85 struct GNUNET_CLIENT_TransmitHandle *transmit_handle;
88 * The locking domain of this request
98 * The status of the lock
100 enum GNUNET_LOCKMANAGER_Status status;
103 * The length of the locking domain string including the trailing NULL
105 uint16_t domain_name_length;
110 * Handler for server replies
112 * @param cls the LOCKMANAGER_Handle
113 * @param msg received message, NULL on timeout or fatal error
116 handle_replies (void *cls,
117 const struct GNUNET_MessageHeader *msg)
120 LOG (GNUNET_ERROR_TYPE_DEBUG,
121 "Lockmanager service not available or went down\n");
124 LOG (GNUNET_ERROR_TYPE_DEBUG,
125 "Received SUCCESS message\n");
130 * Transmit notify for sending message to server
132 * @param cls the message to send
133 * @param size number of bytes available in buf
134 * @param buf where the callee should write the message
135 * @return number of bytes written to buf
138 transmit_notify (void *cls, size_t size, void *buf)
140 struct GNUNET_LOCKMANAGER_Message *msg = cls;
143 if ((0 == size) || (NULL == buf))
145 /* FIXME: Timed out -- requeue? */
148 msg_size = ntohs (msg->header.size);
149 GNUNET_assert (size >= msg_size);
150 memcpy (buf, msg, msg_size);
152 LOG (GNUNET_ERROR_TYPE_DEBUG,
153 "Message of size %u sent\n", msg_size);
159 * Iterator to free hash map entries.
162 * @param key current key code
163 * @param value value in the hash map
164 * @return GNUNET_YES if we should continue to
169 free_iterator(void *cls,
170 const GNUNET_HashCode * key,
173 LOG (GNUNET_ERROR_TYPE_DEBUG,
174 "Clearing locking request\n");
181 * Generate hash with domain name and the lock
183 * @param domain NULL terminated domain name
185 * @param domain_length the length of the domain name including the terminating
186 * NULL if already known; 0 to calculate
188 * @param lock the lock number
189 * @param where to write the generated hash
192 hash_domain_and_lock (const char *domain,
193 uint16_t domain_length,
195 GNUNET_HashCode *ret)
197 unsigned int str_len;
201 str_len = (0 == domain_length) ? strlen (domain) : domain_length - 1;
202 block_size = sizeof (uint32_t) + str_len;
203 block = GNUNET_malloc (block_size);
206 memcpy (&block[1], domain, str_len);
208 GNUNET_CRYPTO_hash (block, block_size, ret);
212 /*******************/
213 /* API Definitions */
214 /*******************/
217 * Connect to the lockmanager service
219 * @param cfg the configuration to use
221 * @return upon success the handle to the service; NULL upon error
223 struct GNUNET_LOCKMANAGER_Handle *
224 GNUNET_LOCKMANAGER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
226 struct GNUNET_LOCKMANAGER_Handle *h;
228 LOG (GNUNET_ERROR_TYPE_DEBUG, "%s()\n", __func__);
229 h = GNUNET_malloc (sizeof (struct GNUNET_LOCKMANAGER_Handle));
230 h->conn = GNUNET_CLIENT_connect ("lockmanager", cfg);
234 LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__);
238 h->hashmap = GNUNET_CONTAINER_multihashmap_create (15);
239 GNUNET_assert (NULL != h->hashmap);
241 GNUNET_CLIENT_receive (h->conn,
244 GNUNET_TIME_UNIT_FOREVER_REL);
246 LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__);
252 * Disconnect from the lockmanager service
254 * @param handle the handle to the lockmanager service
257 GNUNET_LOCKMANAGER_disconnect (struct GNUNET_LOCKMANAGER_Handle *handle)
259 LOG (GNUNET_ERROR_TYPE_DEBUG, "%s()\n", __func__);
260 GNUNET_CLIENT_disconnect (handle->conn);
262 if (0 != GNUNET_CONTAINER_multihashmap_size (handle->hashmap))
264 LOG (GNUNET_ERROR_TYPE_WARNING,
265 "Some locking requests are still present. Cancel them before "
266 "calling %s\n", __func__);
267 GNUNET_CONTAINER_multihashmap_iterate (handle->hashmap,
271 GNUNET_CONTAINER_multihashmap_destroy (handle->hashmap);
273 GNUNET_free (handle);
274 LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__);
279 * Tries to acquire the given lock(even if the lock has been lost) until the
280 * request is called. If the lock is available the status_cb will be
281 * called. If the lock is busy then the request is queued and status_cb
282 * will be called when the lock has been made available and acquired by us.
284 * @param handle the handle to the lockmanager service
286 * @param domain_name name of the locking domain. Clients who want to share
287 * locks must use the same name for the locking domain. Also the
288 * domain_name should be selected with the prefix
289 * "GNUNET_<PROGRAM_NAME>_" to avoid domain name collisions.
292 * @param lock which lock to lock
294 * @param status_cb the callback for signalling when the lock is acquired and
297 * @param status_cb_cls the closure to the above callback
299 * @return the locking request handle for this request. It will be invalidated
300 * when status_cb is called.
302 struct GNUNET_LOCKMANAGER_LockingRequest *
303 GNUNET_LOCKMANAGER_acquire_lock (struct GNUNET_LOCKMANAGER_Handle *handle,
304 const char *domain_name,
306 GNUNET_LOCKMANAGER_StatusCallback
310 struct GNUNET_LOCKMANAGER_LockingRequest *r;
311 struct GNUNET_LOCKMANAGER_Message *msg;
312 struct GNUNET_HashCode hash;
315 LOG (GNUNET_ERROR_TYPE_DEBUG, "%s()\n", __func__);
316 r = GNUNET_malloc (sizeof (struct GNUNET_LOCKMANAGER_LockingRequest));
317 r->domain_name_length = strlen (domain_name) + 1;
320 r->domain = GNUNET_malloc (r->domain_name_length);
321 memcpy (r->domain, domain_name, r->domain_name_length);
323 msg_size = sizeof (struct GNUNET_LOCKMANAGER_Message) + r->domain_name_length;
324 msg = GNUNET_malloc (msg_size);
325 msg->header.type = htons (GNUNET_MESSAGE_TYPE_LOCKMANAGER_ACQUIRE);
326 msg->header.size = htons (msg_size);
327 msg->lock = htonl (lock);
328 memcpy (&msg[1], r->domain, r->domain_name_length);
330 LOG (GNUNET_ERROR_TYPE_DEBUG, "Queueing ACQUIRE message\n");
332 GNUNET_CLIENT_notify_transmit_ready (r->handle->conn,
338 hash_domain_and_lock (r->domain,
339 r->domain_name_length,
342 GNUNET_CONTAINER_multihashmap_put (r->handle->hashmap,
345 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
347 LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__);
354 * Function to cancel the locking request generated by
355 * GNUNET_LOCKMANAGER_acquire_lock. If the lock is acquired us then the lock is
356 * released. GNUNET_LOCKMANAGER_StatusCallback will not be called upon any
357 * status changes resulting due to this call.
359 * @param request the LockingRequest to cancel
362 GNUNET_LOCKMANAGER_cancel_request (struct GNUNET_LOCKMANAGER_LockingRequest
365 struct GNUNET_HashCode hash;
367 LOG (GNUNET_ERROR_TYPE_DEBUG, "%s()\n", __func__);
368 /* FIXME: Stop ACQUIRE retransmissions */
369 if (GNUNET_LOCKMANAGER_SUCCESS == request->status)
371 struct GNUNET_LOCKMANAGER_Message *msg;
374 msg_size = sizeof (struct GNUNET_LOCKMANAGER_Message)
375 + request->domain_name_length;
376 msg = GNUNET_malloc (msg_size);
377 msg->header.type = htons (GNUNET_MESSAGE_TYPE_LOCKMANAGER_RELEASE);
378 msg->header.size = htons (msg_size);
379 msg->lock = htonl (request->lock);
380 memcpy (&msg[1], request->domain, request->domain_name_length);
382 GNUNET_CLIENT_notify_transmit_ready (request->handle->conn,
384 TIMEOUT, /* What if this fails */
389 LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__);
391 hash_domain_and_lock (request->domain,
392 request->domain_name_length,
396 GNUNET_assert (GNUNET_YES ==
397 GNUNET_CONTAINER_multihashmap_remove
398 (request->handle->hashmap, &hash, request));
400 GNUNET_free (request);