-test cases setup for lockmanager
[oweals/gnunet.git] / src / lockmanager / lockmanager_api.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/lockmanager_api.c
23  * @brief API implementation of gnunet_lockmanager_service.h
24  * @author Sree Harsha Totakura
25  */
26
27 #include "platform.h"
28 #include "gnunet_common.h"
29 #include "gnunet_protocols.h"
30 #include "gnunet_client_lib.h"
31 #include "gnunet_lockmanager_service.h"
32
33 #include "lockmanager.h"
34
35 #define LOG(kind,...) \
36   GNUNET_log_from (kind, "lockmanager-api",__VA_ARGS__)
37
38 #define TIME_REL_MINS(min) \
39   GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, min)
40
41 #define TIMEOUT TIME_REL_MINS(3)
42
43 /**
44  * Handler for the lockmanager service
45  */
46 struct GNUNET_LOCKMANAGER_Handle
47 {
48   /**
49    * The client connection to the service
50    */
51   struct GNUNET_CLIENT_Connection *conn;
52 };
53
54
55 /**
56  * Structure for Locking Request
57  */
58 struct GNUNET_LOCKMANAGER_LockingRequest
59 {
60   /**
61    * The handle associated with this request
62    */
63   struct GNUNET_LOCKMANAGER_Handle *handle;
64
65   /**
66    * The status callback
67    */
68   GNUNET_LOCKMANAGER_StatusCallback status_cb;
69
70   /**
71    * Closure for the status callback
72    */
73   void *status_cb_cls;
74
75   /**
76    * The pending transmit handle for the ACQUIRE message
77    */
78   struct GNUNET_CLIENT_TransmitHandle *transmit_handle;
79
80   /**
81    * The locking domain of this request
82    */
83   char *domain;
84   
85   /**
86    * The lock
87    */
88   uint32_t lock;
89
90   /**
91    * The status of the lock
92    */
93   enum GNUNET_LOCKMANAGER_Status status;
94
95   /**
96    * The length of the locking domain string including the trailing NULL
97    */
98   uint16_t domain_name_length;
99 };
100
101
102 /**
103  * Message handler for SUCCESS messages
104  *
105  * @param cls the LOCKMANAGER_Handle
106  * @param msg message received, NULL on timeout or fatal error
107  */
108 static void 
109 handle_success (void *cls,
110                 const struct GNUNET_MessageHeader *msg)
111 {
112   if (NULL == msg)
113     return;
114
115   LOG (GNUNET_ERROR_TYPE_DEBUG,
116        "Received SUCCESS message\n");
117 }
118
119
120 /**
121  * We wait for DUMMY message which will never be sent by the server. However,
122  * in case the server shuts-down/crashes/restarts we are notified by this call
123  * back with a NULL for msg.
124  *
125  * @param cls closure
126  * @param msg message received, NULL on timeout or fatal error
127  */
128 static void
129 handle_server_crash (void *cls,
130                      const struct GNUNET_MessageHeader *msg)
131 {
132   LOG (GNUNET_ERROR_TYPE_DEBUG,
133        "Lockmanager service not available or went down\n");
134
135 }
136
137
138 /**
139  * Transmit notify for sending message to server
140  *
141  * @param cls the message to send
142  * @param size number of bytes available in buf
143  * @param buf where the callee should write the message
144  * @return number of bytes written to buf
145  */
146 static size_t 
147 transmit_notify (void *cls, size_t size, void *buf)
148 {
149   struct GNUNET_LOCKMANAGER_Message *msg = cls;
150   uint16_t msg_size;
151
152   if ((0 == size) || (NULL == buf))
153     {
154       /* FIXME: Timed out -- requeue? */
155       return 0;
156     }
157   msg_size = ntohs (msg->header.size);
158   GNUNET_assert (size >= msg_size);
159   memcpy (buf, msg, msg_size);
160   GNUNET_free (msg);
161   return msg_size;
162 }
163
164
165
166 /*******************/
167 /* API Definitions */
168 /*******************/
169
170 /**
171  * Connect to the lockmanager service
172  *
173  * @param cfg the configuration to use
174  *
175  * @return upon success the handle to the service; NULL upon error
176  */
177 struct GNUNET_LOCKMANAGER_Handle *
178 GNUNET_LOCKMANAGER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
179 {
180   struct GNUNET_LOCKMANAGER_Handle *h;
181
182   LOG (GNUNET_ERROR_TYPE_DEBUG, "%s()\n", __func__);
183   h = GNUNET_malloc (sizeof (struct GNUNET_LOCKMANAGER_Handle));
184   h->conn = GNUNET_CLIENT_connect ("lockmanager", cfg);
185   if (NULL == h->conn)
186     {
187       GNUNET_free (h);
188       LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__);
189       return NULL;
190     }
191   
192   GNUNET_CLIENT_receive (h->conn,
193                          &handle_server_crash,
194                          NULL,
195                          GNUNET_TIME_UNIT_FOREVER_REL);
196   
197   /* FIXME: Assertions fail in client.c if trying to receive multiple messages */
198   /* GNUNET_CLIENT_receive (h->conn, */
199   /*                        &handle_success, */
200   /*                        h, */
201   /*                        GNUNET_TIME_UNIT_FOREVER_REL); */
202
203   LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__);
204   return h;
205 }
206
207
208 /**
209  * Disconnect from the lockmanager service
210  *
211  * @param handle the handle to the lockmanager service
212  */
213 void
214 GNUNET_LOCKMANAGER_disconnect (struct GNUNET_LOCKMANAGER_Handle *handle)
215 {
216   LOG (GNUNET_ERROR_TYPE_DEBUG, "%s()\n", __func__);
217   GNUNET_CLIENT_disconnect (handle->conn);
218   GNUNET_free (handle);
219   LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__);
220 }
221
222
223 /**
224  * Tries to acquire the given lock(even if the lock has been lost) until the
225  * request is called. If the lock is available the status_cb will be
226  * called. If the lock is busy then the request is queued and status_cb
227  * will be called when the lock has been made available and acquired by us.
228  *
229  * @param handle the handle to the lockmanager service
230  *
231  * @param domain_name name of the locking domain. Clients who want to share
232  *          locks must use the same name for the locking domain. Also the
233  *          domain_name should be selected with the prefix
234  *          "GNUNET_<PROGRAM_NAME>_" to avoid domain name collisions.
235  *
236  *
237  * @param lock which lock to lock
238  *
239  * @param status_cb the callback for signalling when the lock is acquired and
240  *          when it is lost
241  *
242  * @param status_cb_cls the closure to the above callback
243  *
244  * @return the locking request handle for this request. It will be invalidated
245  *           when status_cb is called.
246  */
247 struct GNUNET_LOCKMANAGER_LockingRequest *
248 GNUNET_LOCKMANAGER_acquire_lock (struct GNUNET_LOCKMANAGER_Handle *handle,
249                                  const char *domain_name,
250                                  uint32_t lock,
251                                  GNUNET_LOCKMANAGER_StatusCallback
252                                  status_cb,
253                                  void *status_cb_cls)
254 {
255   struct GNUNET_LOCKMANAGER_LockingRequest *r;
256   struct GNUNET_LOCKMANAGER_Message *msg;
257   uint16_t msg_size;
258   
259   LOG (GNUNET_ERROR_TYPE_DEBUG, "%s()\n", __func__);
260   r = GNUNET_malloc (sizeof (struct GNUNET_LOCKMANAGER_LockingRequest));
261   r->domain_name_length = strlen (domain_name) + 1;
262   r->handle = handle;
263   r->lock = lock;
264   r->domain = GNUNET_malloc (r->domain_name_length);
265   memcpy (r->domain, domain_name, r->domain_name_length);
266   
267   msg_size = sizeof (struct GNUNET_LOCKMANAGER_Message) + r->domain_name_length;
268   msg = GNUNET_malloc (msg_size);
269   msg->header.type = htons (GNUNET_MESSAGE_TYPE_LOCKMANAGER_ACQUIRE);
270   msg->header.size = htons (msg_size);
271   msg->lock = htonl (lock);
272   memcpy (&msg[1], r->domain, r->domain_name_length);
273   
274   r->transmit_handle =
275     GNUNET_CLIENT_notify_transmit_ready (r->handle->conn,
276                                          msg_size,
277                                          TIMEOUT,
278                                          GNUNET_NO,
279                                          *transmit_notify,
280                                          msg);
281   LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__);
282   return r;
283 }
284
285
286
287 /**
288  * Function to cancel the locking request generated by
289  * GNUNET_LOCKMANAGER_acquire_lock. If the lock is acquired us then the lock is
290  * released. GNUNET_LOCKMANAGER_StatusCallback will not be called upon any
291  * status changes resulting due to this call.
292  *
293  * @param request the LockingRequest to cancel
294  */
295 void
296 GNUNET_LOCKMANAGER_cancel_request (struct GNUNET_LOCKMANAGER_LockingRequest
297                                    *request)
298 {
299   LOG (GNUNET_ERROR_TYPE_DEBUG, "%s()\n", __func__);
300   /* FIXME: Stop ACQUIRE retransmissions */
301   if (GNUNET_LOCKMANAGER_SUCCESS == request->status)
302     {
303       struct GNUNET_LOCKMANAGER_Message *msg;
304       uint16_t msg_size;
305
306       msg_size = sizeof (struct GNUNET_LOCKMANAGER_Message) 
307         + request->domain_name_length;
308       msg = GNUNET_malloc (msg_size);
309       msg->header.type = htons (GNUNET_MESSAGE_TYPE_LOCKMANAGER_RELEASE);
310       msg->header.size = htons (msg_size);
311       msg->lock = htonl (request->lock);
312       memcpy (&msg[1], request->domain, request->domain_name_length);
313       
314       GNUNET_CLIENT_notify_transmit_ready (request->handle->conn,
315                                            msg_size,
316                                            TIMEOUT, /* What if this fails */
317                                            GNUNET_NO,
318                                            &transmit_notify,
319                                            msg);
320     }
321     LOG (GNUNET_ERROR_TYPE_DEBUG, "%s() END\n", __func__);
322   GNUNET_free (request);
323 }