-extended lockmanager api
[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        "Lockmanger service 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   h = GNUNET_malloc (sizeof (struct GNUNET_LOCKMANAGER_Handle));
183   h->conn = GNUNET_CLIENT_connect ("lockmanager", cfg);
184   if (NULL == h->conn)
185     {
186       GNUNET_free (h);
187       return NULL;
188     }
189   
190   GNUNET_CLIENT_receive (h->conn,
191                          &handle_server_crash,
192                          NULL,
193                          GNUNET_TIME_UNIT_FOREVER_REL);
194   
195   GNUNET_CLIENT_receive (h->conn,
196                          &handle_success,
197                          h,
198                          GNUNET_TIME_UNIT_FOREVER_REL);
199   return h;
200 }
201
202
203 /**
204  * Disconnect from the lockmanager service
205  *
206  * @param handle the handle to the lockmanager service
207  */
208 void
209 GNUNET_LOCKMANAGER_disconnect (struct GNUNET_LOCKMANAGER_Handle *handle)
210 {
211   GNUNET_CLIENT_disconnect (handle->conn);
212   GNUNET_free (handle);
213 }
214
215
216 /**
217  * Tries to acquire the given lock(even if the lock has been lost) until the
218  * request is called. If the lock is available the status_cb will be
219  * called. If the lock is busy then the request is queued and status_cb
220  * will be called when the lock has been made available and acquired by us.
221  *
222  * @param handle the handle to the lockmanager service
223  *
224  * @param domain_name name of the locking domain. Clients who want to share
225  *          locks must use the same name for the locking domain. Also the
226  *          domain_name should be selected with the prefix
227  *          "GNUNET_<PROGRAM_NAME>_" to avoid domain name collisions.
228  *
229  *
230  * @param lock which lock to lock
231  *
232  * @param status_cb the callback for signalling when the lock is acquired and
233  *          when it is lost
234  *
235  * @param status_cb_cls the closure to the above callback
236  *
237  * @return the locking request handle for this request. It will be invalidated
238  *           when status_cb is called.
239  */
240 struct GNUNET_LOCKMANAGER_LockingRequest *
241 GNUNET_LOCKMANAGER_acquire_lock (struct GNUNET_LOCKMANAGER_Handle *handle,
242                                  const char *domain_name,
243                                  uint32_t lock,
244                                  GNUNET_LOCKMANAGER_StatusCallback
245                                  status_cb,
246                                  void *status_cb_cls)
247 {
248   struct GNUNET_LOCKMANAGER_LockingRequest *r;
249   struct GNUNET_LOCKMANAGER_Message *msg;
250   uint16_t msg_size;
251   
252
253   r = GNUNET_malloc (sizeof (struct GNUNET_LOCKMANAGER_LockingRequest));
254   r->domain_name_length = strlen (domain_name) + 1;
255   r->handle = handle;
256   r->lock = lock;
257   r->domain = GNUNET_malloc (r->domain_name_length);
258   memcpy (r->domain, domain_name, r->domain_name_length);
259   
260   msg_size = sizeof (struct GNUNET_LOCKMANAGER_Message) + r->domain_name_length;
261   msg = GNUNET_malloc (msg_size);
262   msg->header.type = htons (GNUNET_MESSAGE_TYPE_LOCKMANAGER_ACQUIRE);
263   msg->header.size = htons (msg_size);
264   msg->lock = htonl (lock);
265   memcpy (&msg[1], r->domain, r->domain_name_length);
266   
267   r->transmit_handle =
268     GNUNET_CLIENT_notify_transmit_ready (r->handle->conn,
269                                          msg_size,
270                                          TIMEOUT,
271                                          GNUNET_NO,
272                                          *transmit_notify,
273                                          msg);
274   return r;
275 }
276
277
278
279 /**
280  * Function to cancel the locking request generated by
281  * GNUNET_LOCKMANAGER_acquire_lock. If the lock is acquired us then the lock is
282  * released. GNUNET_LOCKMANAGER_StatusCallback will not be called upon any
283  * status changes resulting due to this call.
284  *
285  * @param request the LockingRequest to cancel
286  */
287 void
288 GNUNET_LOCKMANAGER_cancel_request (struct GNUNET_LOCKMANAGER_LockingRequest
289                                    *request)
290 {
291   /* FIXME: Stop ACQUIRE retransmissions */
292   if (GNUNET_LOCKMANAGER_SUCCESS == request->status)
293     {
294       struct GNUNET_LOCKMANAGER_Message *msg;
295       uint16_t msg_size;
296
297       msg_size = sizeof (struct GNUNET_LOCKMANAGER_Message) 
298         + request->domain_name_length;
299       msg = GNUNET_malloc (msg_size);
300       msg->header.type = htons (GNUNET_MESSAGE_TYPE_LOCKMANAGER_RELEASE);
301       msg->header.size = htons (msg_size);
302       msg->lock = htonl (request->lock);
303       memcpy (&msg[1], request->domain, request->domain_name_length);
304       
305       GNUNET_CLIENT_notify_transmit_ready (request->handle->conn,
306                                            msg_size,
307                                            TIMEOUT, /* What if this fails */
308                                            GNUNET_NO,
309                                            &transmit_notify,
310                                            msg);
311     }
312   GNUNET_free (request);
313 }