2 This file is part of GNUnet.
3 (C) 2009, 2010, 2011 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 3, 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 dht/gnunet-service-dht_clients.c
23 * @brief GNUnet DHT service's client management code
24 * @author Supriti Singh
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"
38 * Linked list of messages to send to clients.
43 * Pointer to next item in the list
45 struct PendingMessage *next;
48 * Pointer to previous item in the list
50 struct PendingMessage *prev;
53 * Actual message to be sent, allocated at the end of the struct:
54 * // msg = (cast) &pm[1];
55 * // memcpy (&pm[1], data, len);
57 const struct GNUNET_MessageHeader *msg;
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.
69 * Linked list of active clients
71 struct ClientList *next;
74 * Linked list of active clients
76 struct ClientList *prev;
79 * The handle to this client
81 struct GNUNET_SERVER_Client *client_handle;
84 * Handle to the current transmission request, NULL
87 struct GNUNET_SERVER_TransmitHandle *transmit_handle;
90 * Linked list of pending messages for this client
92 struct PendingMessage *pending_head;
95 * Tail of linked list of pending messages for this client
97 struct PendingMessage *pending_tail;
103 * List of active clients.
105 static struct ClientList *client_head;
108 * List of active clients.
110 static struct ClientList *client_tail;
113 * Task run to check for messages that need to be sent to a client.
115 * @param client a ClientList, containing the client and any messages to be sent to it
117 static void process_pending_messages (struct ClientList *client);
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
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
128 * @return the number of bytes actually copied, 0 indicates failure
131 send_reply_to_client (void *cls, size_t size, void *buf)
133 struct ClientList *client = cls;
135 struct PendingMessage *reply;
139 client->transmit_handle = NULL;
142 /* client disconnected */
143 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
144 "Client %p disconnected, pending messages will be discarded\n",
145 client->client_handle);
149 while ((NULL != (reply = client->pending_head)) &&
150 (size >= off + (msize = ntohs (reply->msg->size))))
152 GNUNET_CONTAINER_DLL_remove (client->pending_head, client->pending_tail,
154 memcpy (&cbuf[off], reply->msg, msize);
156 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting %u bytes to client %p\n",
157 msize, client->client_handle);
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);
168 * Task run to check for messages that need to be sent to a client.
170 * @param client a ClientList, containing the client and any messages to be sent to it
173 process_pending_messages (struct ClientList *client)
175 if ((client->pending_head == NULL) || (client->transmit_handle != NULL))
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");
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->
191 GNUNET_TIME_UNIT_FOREVER_REL,
192 &send_reply_to_client, client);
197 * Add a PendingMessage to the clients list of messages to be sent
199 * @param client the active client to send the message to
200 * @param pending_message the actual message to send
203 add_pending_message (struct ClientList *client,
204 struct PendingMessage *pending_message)
206 GNUNET_CONTAINER_DLL_insert_tail (client->pending_head, client->pending_tail,
208 process_pending_messages (client);
212 * Find a client if it exists, add it otherwise.
214 * @param client the server handle to the client
216 * @return the client if found, a new client otherwise
218 static struct ClientList *
219 find_active_client (struct GNUNET_SERVER_Client *client)
221 struct ClientList *pos = client_head;
222 struct ClientList *ret;
226 if (pos->client_handle == client)
230 ret = GNUNET_new (struct ClientList);
231 ret->client_handle = client;
232 GNUNET_CONTAINER_DLL_insert (client_head, client_tail, ret);
238 * SUPU: Call made from dht_api.c
239 * Handler for monitor stop messages
241 * @param cls closure for the service
242 * @param client the client we received this message from
243 * @param message the actual message received
247 handle_dht_local_monitor_stop (void *cls, struct GNUNET_SERVER_Client *client,
248 const struct GNUNET_MessageHeader *message)
250 //const struct GNUNET_DHT_MonitorStartStopMessage *msg;
255 * SUPU: Monitor call made from dht_api.c
256 * Handler for monitor start messages
258 * @param cls closure for the service
259 * @param client the client we received this message from
260 * @param message the actual message received
264 handle_dht_local_monitor (void *cls, struct GNUNET_SERVER_Client *client,
265 const struct GNUNET_MessageHeader *message)
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. */
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)
279 * @param cls closure for the service
280 * @param client the client we received this message from
281 * @param message the actual message received
285 handle_dht_local_get_stop (void *cls, struct GNUNET_SERVER_Client *client,
286 const struct GNUNET_MessageHeader *message)
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
298 * FIXME: Call to this function is made whenever we have a get request.
299 * Handler for DHT GET messages from the client.
301 * @param cls closure for the service
302 * @param client the client we received this message from
303 * @param message the actual message received
306 handle_dht_local_get (void *cls, struct GNUNET_SERVER_Client *client,
307 const struct GNUNET_MessageHeader *message)
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;
315 size = ntohs (message->size);
316 if (size < sizeof (struct GNUNET_DHT_ClientGetMessage))
319 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
323 get_msg = (struct GNUNET_DHT_ClientGetMessage *) message;
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. */
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));
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);
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
355 handle_dht_local_put (void *cls, struct GNUNET_SERVER_Client *client,
356 const struct GNUNET_MessageHeader *message)
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 */
363 size = ntohs (message->size);
364 if (size < sizeof (struct GNUNET_DHT_ClientPutMessage))
367 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
371 /* FIXME:Should we define put_msg as const? */
372 put_msg = (struct GNUNET_DHT_ClientPutMessage *) message;
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),
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),
387 &put_msg->key, 0, NULL, &put_msg[1],
389 sizeof (struct GNUNET_DHT_ClientPutMessage),
392 /* FIXME: Here we send back the confirmation before verifying if put was successful
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);
407 * Functions with this signature are called whenever a client
408 * is disconnected on the network level.
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
415 handle_client_disconnect (void *cls,
416 struct GNUNET_SERVER_Client *client)
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. */
425 * Get result from neighbours file.
428 GDS_CLIENTS_process_get_result()
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.
440 * @param server the initialized server
443 GDS_CLIENTS_init (struct GNUNET_SERVER_Handle *server)
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)},
462 GNUNET_SERVER_add_handlers (server, plugin_handlers);
463 GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
467 * SUPU: Call made from gnunet-service-dht.c
468 * Shutdown client subsystem.