added list processing
[oweals/gnunet.git] / src / lockmanager / gnunet-service-lockmanager.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/gnunet-service-lockmanager.c
23  * @brief implementation of the LOCKMANAGER service
24  * @author Sree Harsha Totakura
25  */
26
27 #include "platform.h"
28 #include "gnunet_common.h"
29 #include "gnunet_container_lib.h"
30 #include "gnunet_protocols.h"
31 #include "gnunet_service_lib.h"
32 #include "gnunet_server_lib.h"
33
34 #include "lockmanager.h"
35
36 #define VERBOSE GNUNET_YES
37
38 #define LOG(kind,...) \
39   GNUNET_log (kind, __VA_ARGS__)
40
41 #define TIME_REL_MINS(min) \
42   GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, min)
43
44 #define TIMEOUT TIME_REL_MINS(3)
45
46
47 /**
48  * Doubly linked list of clients waiting for a lock
49  */
50 struct WaitList
51 {
52   /**
53    * The next client structure
54    */
55   struct WaitList *next;
56   
57   /**
58    * The prev client structure
59    */
60   struct WaitList *prev;
61
62   /**
63    * Pointer to the client
64    */
65   struct GNUNET_SERVER_Client *client;
66 };
67
68
69 /**
70  * A Lock element for a doubly linked list
71  */
72 struct LockList
73 {
74   /**
75    * The next element pointer
76    */
77   struct LockList *next;
78
79   /**
80    * Pointer to the previous element
81    */
82   struct LockList *prev;
83
84   /**
85    * The client whizch is currently holding this lock
86    */
87   struct GNUNET_SERVER_Client *client;
88
89   /**
90    * List head of clients waiting for this lock
91    */
92   struct WaitList *wait_list_head;
93
94   /**
95    * List tail of clients waiting for this lock
96    */
97   struct WaitList *wait_list_tail;
98
99   /**
100    * The name of the locking domain this lock belongs to
101    */
102   char *domain_name;
103
104   /**
105    * The number of this lock
106    */
107   uint32_t lock_num;
108 };
109
110
111 /**
112  * Doubly linked list of clients having connections to us
113  */
114 struct ClientList
115 {
116   /**
117    * The next client structure
118    */
119   struct ClientList *next;
120
121   /**
122    * The previous client structure
123    */
124   struct ClientList *prev;
125
126   /**
127    * Pointer to the client
128    */
129   struct GNUNET_SERVER_Client *client;
130 };
131
132
133 /**
134  * Head of the doubly linked list of the currently held locks
135  */
136 static struct LockList *ll_head;
137
138 /**
139  * Tail of the doubly linked list of the currently held locks
140  */
141 static struct LockList *ll_tail;
142
143 /**
144  * Head of the doubly linked list of clients currently connected
145  */
146 static struct ClientList *cl_head;
147
148 /**
149  * Tail of the doubly linked list of clients currently connected
150  */
151 static struct ClientList *cl_tail;
152
153
154
155 /**
156  * Function to search for a lock in lock_list matching the given domain_name and
157  * lock number
158  *
159  * @param domain_name the name of the locking domain
160  * @param lock_num the number of the lock
161  * @param ret this will be the pointer to the corresponding Lock if found; else
162  *         it will be the last element in the locks list
163  * @return GNUNET_YES if a matching lock is present in lock_list; GNUNET_NO if not
164  */
165 static int
166 ll_find_lock (const char *domain_name,
167            const uint32_t lock_num,
168            struct LockList **ret)
169 {
170   struct LockList *current_lock;
171
172   current_lock = ll_head;
173   
174   while (NULL != current_lock)
175     {
176       if ( (0 == strcmp (domain_name, current_lock->domain_name))
177            && (lock_num == current_lock->lock_num))
178         {
179           *ret = current_lock;
180           return GNUNET_YES;
181         }
182
183       current_lock = current_lock->next;
184     }
185   
186   *ret = current_lock;
187   return GNUNET_NO;
188 }
189
190
191 /**
192  * Function to append a lock to the global lock list
193  *
194  * @param domain_name the name of the locking domain
195  * @param domain_name_len the length of the domain name
196  * @param lock_num the number of the lock
197  * @param tail the pointer to the tail of the global lock list
198  */
199 static void
200 ll_add_lock (const char *domain_name,
201           size_t domain_name_len,
202           const uint32_t lock_num)
203 {
204   struct LockList *lock;
205
206   lock = GNUNET_malloc (sizeof (struct LockList));
207   lock->domain_name = GNUNET_malloc (domain_name_len);
208   strncpy (lock->domain_name, domain_name, domain_name_len);
209   lock->lock_num = lock_num;
210   
211   GNUNET_CONTAINER_DLL_insert_tail (ll_head,
212                                     ll_tail,
213                                     lock);
214 }
215
216
217 /**
218  * Function to delete a lock from the lock list
219  *
220  * @param lock the lock to be deleted
221  */
222 static void
223 ll_remove_lock (struct LockList *lock)
224 {
225   GNUNET_assert (NULL != ll_head);
226   GNUNET_CONTAINER_DLL_remove (ll_head,
227                                ll_tail,
228                                lock);
229   GNUNET_free (lock->domain_name);
230   GNUNET_free (lock);
231 }
232
233
234 /**
235  * Find a client in the waiting list of a lock
236  *
237  * @param lock the LockList entry of a lock
238  * @param client the client to look for
239  * @param ret where to store the matched wait list entry
240  * @return GNUNET_YES if a match is found; GNUNET_NO if not
241  */
242 static int
243 ll_wl_find_client (struct LockList *lock,
244                    const struct GNUNET_SERVER_Client *client,
245                    struct WaitList **ret)
246 {
247   struct WaitList *current_wl_entry;
248
249   current_wl_entry = lock->wait_list_head;
250
251   while (NULL != current_wl_entry)
252     {
253       if (client == current_wl_entry->client)
254         {
255           *ret = current_wl_entry;
256           return GNUNET_YES;
257         }
258       current_wl_entry = current_wl_entry->next;
259     }
260   *ret = current_wl_entry;
261   return GNUNET_NO;
262 }
263
264
265 /**
266  * Add a client to the wait list of a lock
267  *
268  * @param lock the lock list entry of a lock
269  * @param client the client to queue for the lock's wait list
270  */
271 static void
272 ll_wl_add_client (struct LockList *lock,
273                   struct GNUNET_SERVER_Client *client)
274 {
275   struct WaitList *wl_entry;
276
277   wl_entry = GNUNET_malloc (sizeof (struct WaitList));
278   wl_entry->client = client;
279   GNUNET_CONTAINER_DLL_insert_tail (lock->wait_list_head,
280                                     lock->wait_list_tail,
281                                     wl_entry);
282 }
283
284
285 static void
286 ll_wl_remove_client (struct LockList *lock,
287                      struct WaitList *wl_client)
288 {
289   GNUNET_CONTAINER_DLL_remove (lock->wait_list_head,
290                                lock->wait_list_tail,
291                                wl_client);
292
293   GNUNET_free (wl_client);
294 }
295
296
297 /**
298  * Search for a client in the client list
299  *
300  * @param client the client to be searched for
301  * @param ret will be pointing to the matched list entry (if there is a match);
302  *          else to the tail of the client list
303  * @return GNUNET_YES if the client is present; GNUNET_NO if not
304  */
305 static int
306 cl_find_client (const struct GNUNET_SERVER_Client *client,
307                 struct ClientList **ret)
308 {
309   struct ClientList *current;
310
311   current = cl_head;
312
313   while (NULL != current)
314     {
315       if (client == current->client)
316         {
317           *ret = current;
318           return GNUNET_YES;
319         }
320
321       current = current->next;
322     }
323   
324   *ret = current;
325   return GNUNET_NO;
326 }
327
328
329 /**
330  * Append a client to the client list
331  *
332  * @param client the client to be appended to the list
333  */
334 static void
335 cl_add_client (struct GNUNET_SERVER_Client *client)
336 {
337   struct ClientList *new_client;
338
339   new_client = GNUNET_malloc (sizeof (struct ClientList));
340   new_client->client = client;
341   GNUNET_CONTAINER_DLL_insert_tail (cl_head,
342                                     cl_tail,
343                                     new_client);
344 }
345
346
347 /**
348  * Delete the given client from the client list
349  *
350  * @param client the client list entry to delete
351  */
352 static void
353 cl_remove_client (struct ClientList *client)
354 {
355   GNUNET_CONTAINER_DLL_remove (cl_head,
356                                cl_tail,
357                                client);
358   GNUNET_free (client);
359 }
360
361
362 /**
363  * Transmit notify for sending message to client
364  *
365  * @param cls the message to send
366  * @param size number of bytes available in buf
367  * @param buf where the callee should write the message
368  * @return number of bytes written to buf
369  */
370 static size_t 
371 transmit_notify (void *cls, size_t size, void *buf)
372 {
373   struct GNUNET_LOCKMANAGER_Message *msg = cls;
374   uint16_t msg_size;
375
376   if ((0 == size) || (NULL == buf))
377     {
378       /* FIXME: Timed out -- requeue? */
379       return 0;
380     }
381   msg_size = ntohs (msg->header.size);
382   GNUNET_assert (size >= msg_size);
383   memcpy (buf, msg, msg_size);
384   GNUNET_free (msg);
385   LOG (GNUNET_ERROR_TYPE_DEBUG,
386        "Message of size %u sent\n", msg_size);
387   return msg_size;
388 }
389
390
391 /**
392  * Handler for GNUNET_MESSAGE_TYPE_LOCKMANAGER_ACQUIRE
393  *
394  * @param cls NULL
395  * @param client the client sending this message
396  * @param message GNUNET_MESSAGE_TYPE_LOCKMANAGER_ACQUIRE message
397  */
398 static void
399 handle_acquire (void *cls,
400                 struct GNUNET_SERVER_Client *client,
401                 const struct GNUNET_MessageHeader *message)
402 {
403   const struct GNUNET_LOCKMANAGER_Message *request;
404   struct GNUNET_LOCKMANAGER_Message *reply;
405   int16_t request_size;
406   
407
408   LOG (GNUNET_ERROR_TYPE_DEBUG,
409        "Received an ACQUIRE message\n");
410   
411   request = (struct GNUNET_LOCKMANAGER_Message *) message;
412
413   /* FIXME: Dummy implementation; just echos success for every lock */
414   request_size = ntohs (message->size);
415   reply = GNUNET_malloc (request_size);
416   memcpy (reply, request, request_size);
417   reply->header.type = htons (GNUNET_MESSAGE_TYPE_LOCKMANAGER_SUCCESS);
418   GNUNET_SERVER_notify_transmit_ready (client,
419                                        request_size,
420                                        TIMEOUT,
421                                        &transmit_notify,
422                                        reply);
423
424   GNUNET_SERVER_receive_done (client, GNUNET_OK);
425 }
426
427
428 /**
429  * Handle for GNUNET_MESSAGE_TYPE_LOCKMANAGER_RELEASE
430  *
431  * @param cls NULL
432  * @param client the client sending this message
433  * @param message the LOCKMANAGER_RELEASE message
434  */
435 static void
436 handle_release (void *cls,
437                 struct GNUNET_SERVER_Client *client,
438                 const struct GNUNET_MessageHeader *message)
439 {
440   LOG (GNUNET_ERROR_TYPE_DEBUG,
441        "Received a RELEASE message\n");
442
443   GNUNET_SERVER_receive_done (client, GNUNET_OK);
444 }
445
446
447 /**
448  * Lock manager setup
449  *
450  * @param cls closure
451  * @param server the initialized server
452  * @param cfg configuration to use
453  */
454 static void 
455 lockmanager_run (void *cls,
456                  struct GNUNET_SERVER_Handle * server,
457                  const struct GNUNET_CONFIGURATION_Handle *cfg)
458 {
459   static const struct GNUNET_SERVER_MessageHandler message_handlers[] =
460     {
461       {&handle_acquire, NULL, GNUNET_MESSAGE_TYPE_LOCKMANAGER_ACQUIRE, 0},
462       {&handle_release, NULL, GNUNET_MESSAGE_TYPE_LOCKMANAGER_RELEASE, 0},
463       {NULL}
464     };
465   
466   LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting lockmanager\n");
467   GNUNET_SERVER_add_handlers (server,
468                               message_handlers);
469   
470 }
471
472 /**
473  * The starting point of execution
474  */
475 int main (int argc, char *const *argv)
476 {
477   int ret;
478   
479   GNUNET_log_setup ("lockmanager",
480 #if VERBOSE
481                     "DEBUG",
482 #else
483                     "WARNING",
484 #endif
485                     NULL);
486
487   LOG (GNUNET_ERROR_TYPE_DEBUG, "main()\n");
488   ret = 
489     (GNUNET_OK ==
490      GNUNET_SERVICE_run (argc,
491                          argv,
492                          "lockmanager",
493                          GNUNET_SERVICE_OPTION_NONE,
494                          &lockmanager_run,
495                          NULL)) ? 0 : 1;
496   LOG (GNUNET_ERROR_TYPE_DEBUG, "main() END\n");
497   return ret;
498 }