-doxygen
[oweals/gnunet.git] / src / dht / gnunet-service-xdht_clients.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010, 2011 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 3, 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 dht/gnunet-service-dht_clients.c
23  * @brief GNUnet DHT service's client management code
24  * @author Supriti Singh
25  */
26
27 #include "platform.h"
28 #include "gnunet_constants.h"
29 #include "gnunet_protocols.h"
30 #include "gnunet_statistics_service.h"
31 #include "gnunet-service-xdht.h"
32 #include "gnunet-service-xdht_clients.h"
33 #include "gnunet-service-xdht_datacache.h"
34 #include "gnunet-service-xdht_neighbours.h"
35 #include "dht.h"
36
37 /**
38  * Linked list of messages to send to clients.
39  */
40 struct PendingMessage
41 {
42   /**
43    * Pointer to next item in the list
44    */
45   struct PendingMessage *next;
46
47   /**
48    * Pointer to previous item in the list
49    */
50   struct PendingMessage *prev;
51
52   /**
53    * Actual message to be sent, allocated at the end of the struct:
54    * // msg = (cast) &pm[1];
55    * // memcpy (&pm[1], data, len);
56    */
57   const struct GNUNET_MessageHeader *msg;
58
59 };
60
61 /**
62  * Struct containing information about a client,
63  * handle to connect to it, and any pending messages
64  * that need to be sent to it.
65  */
66 struct ClientList
67 {
68   /**
69    * Linked list of active clients
70    */
71   struct ClientList *next;
72
73   /**
74    * Linked list of active clients
75    */
76   struct ClientList *prev;
77
78   /**
79    * The handle to this client
80    */
81   struct GNUNET_SERVER_Client *client_handle;
82
83   /**
84    * Handle to the current transmission request, NULL
85    * if none pending.
86    */
87   struct GNUNET_SERVER_TransmitHandle *transmit_handle;
88
89   /**
90    * Linked list of pending messages for this client
91    */
92   struct PendingMessage *pending_head;
93
94   /**
95    * Tail of linked list of pending messages for this client
96    */
97   struct PendingMessage *pending_tail;
98
99 };
100
101
102 /**
103  * List of active clients.
104  */
105 static struct ClientList *client_head;
106
107 /**
108  * List of active clients.
109  */
110 static struct ClientList *client_tail;
111
112 /**
113  * Task run to check for messages that need to be sent to a client.
114  *
115  * @param client a ClientList, containing the client and any messages to be sent to it
116  */
117 static void process_pending_messages (struct ClientList *client);
118 /**
119  * Callback called as a result of issuing a GNUNET_SERVER_notify_transmit_ready
120  * request.  A ClientList is passed as closure, take the head of the list
121  * and copy it into buf, which has the result of sending the message to the
122  * client.
123  *
124  * @param cls closure to this call
125  * @param size maximum number of bytes available to send
126  * @param buf where to copy the actual message to
127  *
128  * @return the number of bytes actually copied, 0 indicates failure
129  */
130 static size_t
131 send_reply_to_client (void *cls, size_t size, void *buf)
132 {
133   struct ClientList *client = cls;
134   char *cbuf = buf;
135   struct PendingMessage *reply;
136   size_t off;
137   size_t msize;
138
139   client->transmit_handle = NULL;
140   if (buf == NULL)
141   {
142     /* client disconnected */
143     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
144                 "Client %p disconnected, pending messages will be discarded\n",
145                 client->client_handle);
146     return 0;
147   }
148   off = 0;
149   while ((NULL != (reply = client->pending_head)) &&
150          (size >= off + (msize = ntohs (reply->msg->size))))
151   {
152     GNUNET_CONTAINER_DLL_remove (client->pending_head, client->pending_tail,
153                                  reply);
154     memcpy (&cbuf[off], reply->msg, msize);
155     GNUNET_free (reply);
156     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting %u bytes to client %p\n",
157                 msize, client->client_handle);
158     off += msize;
159   }
160   process_pending_messages (client);
161   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitted %u/%u bytes to client %p\n",
162               (unsigned int) off, (unsigned int) size, client->client_handle);
163   return off;
164 }
165
166
167 /**
168  * Task run to check for messages that need to be sent to a client.
169  *
170  * @param client a ClientList, containing the client and any messages to be sent to it
171  */
172 static void
173 process_pending_messages (struct ClientList *client)
174 {
175   if ((client->pending_head == NULL) || (client->transmit_handle != NULL))
176   {
177     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
178                 "Not asking for transmission to %p now: %s\n",
179                 client->client_handle,
180                 client->pending_head ==
181                 NULL ? "no more messages" : "request already pending");
182     return;
183   }
184   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
185               "Asking for transmission of %u bytes to client %p\n",
186               ntohs (client->pending_head->msg->size), client->client_handle);
187   client->transmit_handle =
188       GNUNET_SERVER_notify_transmit_ready (client->client_handle,
189                                            ntohs (client->pending_head->
190                                                   msg->size),
191                                            GNUNET_TIME_UNIT_FOREVER_REL,
192                                            &send_reply_to_client, client);
193 }
194
195
196 /**
197  * Add a PendingMessage to the clients list of messages to be sent
198  *
199  * @param client the active client to send the message to
200  * @param pending_message the actual message to send
201  */
202 static void
203 add_pending_message (struct ClientList *client,
204                      struct PendingMessage *pending_message)
205 {
206   GNUNET_CONTAINER_DLL_insert_tail (client->pending_head, client->pending_tail,
207                                     pending_message);
208   process_pending_messages (client);
209 }
210
211 /**
212  * Find a client if it exists, add it otherwise.
213  *
214  * @param client the server handle to the client
215  *
216  * @return the client if found, a new client otherwise
217  */
218 static struct ClientList *
219 find_active_client (struct GNUNET_SERVER_Client *client)
220 {
221   struct ClientList *pos = client_head;
222   struct ClientList *ret;
223
224   while (pos != NULL)
225   {
226     if (pos->client_handle == client)
227       return pos;
228     pos = pos->next;
229   }
230   ret = GNUNET_new (struct ClientList);
231   ret->client_handle = client;
232   GNUNET_CONTAINER_DLL_insert (client_head, client_tail, ret);
233   return ret;
234 }
235
236
237 /**
238  * SUPU: Call made from dht_api.c
239  * Handler for monitor stop messages
240  *
241  * @param cls closure for the service
242  * @param client the client we received this message from
243  * @param message the actual message received
244  *
245  */
246 static void
247 handle_dht_local_monitor_stop (void *cls, struct GNUNET_SERVER_Client *client,
248                                const struct GNUNET_MessageHeader *message)
249 {
250   //const struct GNUNET_DHT_MonitorStartStopMessage *msg;
251 }
252
253
254 /**
255  * SUPU: Monitor call made from dht_api.c
256  * Handler for monitor start messages
257  *
258  * @param cls closure for the service
259  * @param client the client we received this message from
260  * @param message the actual message received
261  *
262  */
263 static void
264 handle_dht_local_monitor (void *cls, struct GNUNET_SERVER_Client *client,
265                           const struct GNUNET_MessageHeader *message)
266 {
267   //const struct GNUNET_DHT_MonitorStartStopMessage *msg;
268   /* FIXME: At the moment I don't know exact usage of monitor message. But most
269    probably it will be just copy and paste from old implementation. */
270 }
271
272
273 /**SUPU: Call to this function is made whenever a client does not want the
274  * get request any more. There is a function in dht_api.c but I don't know
275  * yet how the call is made to this function. 
276  * Handler for any generic DHT stop messages, calls the appropriate handler
277  * depending on message type (if processed locally)
278  *
279  * @param cls closure for the service
280  * @param client the client we received this message from
281  * @param message the actual message received
282  *
283  */
284 static void
285 handle_dht_local_get_stop (void *cls, struct GNUNET_SERVER_Client *client,
286                            const struct GNUNET_MessageHeader *message)
287 {
288    //const struct GNUNET_DHT_ClientGetStopMessage *dht_stop_msg;
289   /* FIXME: Whats the use of get_stop. A client notifies the server to stop asking
290    for the get message. But in case of x-vine, it asks for get only once. So,
291    when it has already send the get message, after that if client asks it to
292    stop, it really can't do anything. Its better to wait for the result, discard
293    it and don't communicate with client about the result instead of generating
294    more traffic.*/
295 }
296
297 /**
298  * FIXME: Call to this function is made whenever we have a get request. 
299  * Handler for DHT GET messages from the client.
300  *
301  * @param cls closure for the service
302  * @param client the client we received this message from
303  * @param message the actual message received
304  */
305 static void
306 handle_dht_local_get (void *cls, struct GNUNET_SERVER_Client *client,
307                       const struct GNUNET_MessageHeader *message)
308 {
309   struct GNUNET_DHT_ClientGetMessage *get_msg;
310   struct GNUNET_PeerIdentity *get_path;
311   struct GNUNET_PeerIdentity *my_identity;
312   unsigned int get_path_length;
313   uint16_t size;
314   
315   size = ntohs (message->size);
316   if (size < sizeof (struct GNUNET_DHT_ClientGetMessage))
317   {
318     GNUNET_break (0);
319     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
320     return;
321   }
322   
323   get_msg = (struct GNUNET_DHT_ClientGetMessage *) message;
324   
325   /* FIXME: Search locally? Why should we always search locally? 
326    Current implementation of datacache needs to be modified. If found here, then
327    notify the requesting client. */
328   
329   /* FIXME: Call GDS_NEIGHBOURS_handle_get
330    Here you need to remember the whole path because you need to travel that path
331    and reach back here with the result. So, you should send your own id, client
332    id, get path, get path length. You also need to add yourself to the get path.  */
333   my_identity = GDS_NEIGHBOURS_get_id();
334   get_path = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
335   memcpy (get_path, &my_identity, sizeof (struct GNUNET_PeerIdentity));
336   get_path_length = 1;
337   
338   /* FIXME:
339    * 1. Find some unique identifier for the client.
340    * 2. Also, I don't know the usage of block, replication and type. So, I
341    * am not sending the parameters now.  */
342   GDS_NEIGHBOURS_handle_get (my_identity, get_path, get_path_length,
343                              &(get_msg->key), NULL, NULL, NULL);
344   
345 }
346
347
348 /**
349  * Handler for PUT messages.
350  * @param cls closure for the service
351  * @param client the client we received this message from
352  * @param message the actual message received
353  */
354 static void
355 handle_dht_local_put (void *cls, struct GNUNET_SERVER_Client *client,
356                       const struct GNUNET_MessageHeader *message)
357 {
358   struct GNUNET_DHT_ClientPutMessage *put_msg;
359   struct GNUNET_DHT_ClientPutConfirmationMessage *conf;
360   struct PendingMessage *pm;
361   uint16_t size; /* FIXME: When to use size_t and when uint16_t */
362   
363   size = ntohs (message->size);
364   if (size < sizeof (struct GNUNET_DHT_ClientPutMessage))
365   {
366     GNUNET_break (0);
367     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
368     return;
369   }
370   
371   /* FIXME:Should we define put_msg as const? */
372   put_msg = (struct GNUNET_DHT_ClientPutMessage *) message;
373   
374   /* store locally. FIXME: Is it secure to allow each peer to store the data? */
375   GDS_DATACACHE_handle_put (GNUNET_TIME_absolute_ntoh (put_msg->expiration),
376                             &put_msg->key, 0, NULL, ntohl (put_msg->type),
377                             size - sizeof (struct GNUNET_DHT_ClientPutMessage),
378                             &put_msg[1]);
379   
380   /* FIXME: Right now I have just kept all the fields from the old function.
381    It may be possible that most of them are not needed. Check and remove if
382    not needed. Usage of replication, options and type is still not clear. */
383   GDS_NEIGHBOURS_handle_put (ntohl (put_msg->type), ntohl (put_msg->options),
384                              ntohl (put_msg->desired_replication_level),
385                              GNUNET_TIME_absolute_ntoh (put_msg->expiration),
386                              0 /* hop count */ ,
387                              &put_msg->key, 0, NULL, &put_msg[1],
388                              size -
389                              sizeof (struct GNUNET_DHT_ClientPutMessage),
390                              NULL, NULL, NULL);
391   
392   /* FIXME: Here we send back the confirmation before verifying if put was successful
393    or not. */
394   pm = GNUNET_malloc (sizeof (struct PendingMessage) +
395                       sizeof (struct GNUNET_DHT_ClientPutConfirmationMessage));
396   conf = (struct GNUNET_DHT_ClientPutConfirmationMessage *) &pm[1];
397   conf->header.size = htons (sizeof (struct GNUNET_DHT_ClientPutConfirmationMessage));
398   conf->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_CLIENT_PUT_OK);
399   conf->reserved = htonl (0);
400   conf->unique_id = put_msg->unique_id;
401   pm->msg = &conf->header;
402   add_pending_message (find_active_client (client), pm);
403   GNUNET_SERVER_receive_done (client, GNUNET_OK);
404 }
405
406 /**
407  * Functions with this signature are called whenever a client
408  * is disconnected on the network level.
409  *
410  * @param cls closure (NULL for dht)
411  * @param client identification of the client; NULL
412  *        for the last call when the server is destroyed
413  */
414 static void
415 handle_client_disconnect (void *cls,
416                           struct GNUNET_SERVER_Client *client)
417 {
418   /* You should maintain a list of client attached to this service. Then
419    search for the correct client and stop all its ongoing activites and
420    delete it from the list. */
421 }
422
423
424 /**
425  * Get result from neighbours file. 
426  */
427 void
428 GDS_CLIENTS_process_get_result()
429 {
430   
431 }
432
433
434 /**
435  * SUPU: Call to this function is made from gnunet-service-xdht.c
436  * Here we register handlers for each possible kind of message the service
437  * receives from the clients. 
438  * Initialize client subsystem.
439  *
440  * @param server the initialized server
441  */
442 void
443 GDS_CLIENTS_init (struct GNUNET_SERVER_Handle *server)
444 {
445   static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = {
446     {&handle_dht_local_put, NULL,
447      GNUNET_MESSAGE_TYPE_DHT_CLIENT_PUT, 0},
448     {&handle_dht_local_get, NULL,
449      GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET, 0},
450     {&handle_dht_local_get_stop, NULL,
451      GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET_STOP,
452      sizeof (struct GNUNET_DHT_ClientGetStopMessage)},
453     {&handle_dht_local_monitor, NULL,
454      GNUNET_MESSAGE_TYPE_DHT_MONITOR_START,
455      sizeof (struct GNUNET_DHT_MonitorStartStopMessage)},
456     {&handle_dht_local_monitor_stop, NULL,
457      GNUNET_MESSAGE_TYPE_DHT_MONITOR_STOP,
458      sizeof (struct GNUNET_DHT_MonitorStartStopMessage)},
459     {NULL, NULL, 0, 0}
460   };
461   
462   GNUNET_SERVER_add_handlers (server, plugin_handlers);
463   GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
464 }
465
466 /**
467  * SUPU: Call made from gnunet-service-dht.c
468  * Shutdown client subsystem.
469  */
470 void
471 GDS_CLIENTS_done ()
472 {
473   
474 }