2 This file is part of GNUnet.
3 (C) 2009--2013 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.
23 * @brief library to access the DV service
24 * @author Christian Grothoff
25 * @author Nathan Evans
28 #include "gnunet_util_lib.h"
29 #include "gnunet_dv_service.h"
30 #include "gnunet_protocols.h"
32 #include "gnunet_transport_plugin.h"
34 #define LOG(kind,...) GNUNET_log_from (kind, "dv-api",__VA_ARGS__)
38 * Handle for a send operation.
40 struct GNUNET_DV_TransmitHandle
45 struct GNUNET_DV_TransmitHandle *next;
50 struct GNUNET_DV_TransmitHandle *prev;
53 * Handle to the service.
55 struct GNUNET_DV_ServiceHandle *sh;
58 * Function to call upon completion.
60 GNUNET_DV_MessageSentCallback cb;
68 * The actual message (allocated at the end of this struct).
70 const struct GNUNET_MessageHeader *msg;
73 * Destination for the message.
75 struct GNUNET_PeerIdentity target;
81 * Handle to the DV service.
83 struct GNUNET_DV_ServiceHandle
87 * Connection to DV service.
89 struct GNUNET_CLIENT_Connection *client;
92 * Active request for transmission to DV service.
94 struct GNUNET_CLIENT_TransmitHandle *th;
99 const struct GNUNET_CONFIGURATION_Handle *cfg;
102 * Closure for the callbacks.
107 * Function to call on connect events.
109 GNUNET_DV_ConnectCallback connect_cb;
112 * Function to call on disconnect events.
114 GNUNET_DV_DisconnectCallback disconnect_cb;
117 * Function to call on receiving messages events.
119 GNUNET_DV_MessageReceivedCallback message_cb;
122 * Head of messages to transmit.
124 struct GNUNET_DV_TransmitHandle *th_head;
127 * Tail of messages to transmit.
129 struct GNUNET_DV_TransmitHandle *th_tail;
132 * Mapping of peer identities to TransmitHandles to invoke
133 * upon successful transmission. The respective
134 * transmissions have already been done.
136 struct GNUNET_CONTAINER_MultiHashMap *send_callbacks;
147 * Disconnect and then reconnect to the DV service.
149 * @param sh service handle
152 reconnect (struct GNUNET_DV_ServiceHandle *sh);
156 * Gives a message from our queue to the DV service.
158 * @param cls handle to the dv service (struct GNUNET_DV_ServiceHandle)
159 * @param size how many bytes can we send
160 * @param buf where to copy the message to send
161 * @return how many bytes we copied to buf
164 transmit_pending (void *cls, size_t size, void *buf)
166 struct GNUNET_DV_ServiceHandle *sh = cls;
168 struct GNUNET_DV_TransmitHandle *th;
179 while ( (NULL != (th = sh->th_head)) &&
180 (size - ret >= (tsize = ntohs (th->msg->size)) ))
182 GNUNET_CONTAINER_DLL_remove (sh->th_head,
185 memcpy (&cbuf[ret], th->msg, tsize);
187 (void) GNUNET_CONTAINER_multihashmap_put (sh->send_callbacks,
188 &th->target.hashPubKey,
190 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
197 * Start sending messages from our queue to the service.
199 * @param sh service handle
202 start_transmit (struct GNUNET_DV_ServiceHandle *sh)
206 if (NULL == sh->th_head)
209 GNUNET_CLIENT_notify_transmit_ready (sh->client,
210 ntohs (sh->th_head->msg->size),
211 GNUNET_TIME_UNIT_FOREVER_REL,
213 &transmit_pending, sh);
218 * Handles a message sent from the DV service to us.
219 * Parse it out and give it to the plugin.
221 * @param cls the handle to the DV API
222 * @param msg the message that was received
225 handle_message_receipt (void *cls,
226 const struct GNUNET_MessageHeader *msg)
228 struct GNUNET_DV_ServiceHandle *sh = cls;
229 const struct GNUNET_DV_ConnectMessage *cm;
230 const struct GNUNET_DV_DisconnectMessage *dm;
231 const struct GNUNET_DV_ReceivedMessage *rm;
232 const struct GNUNET_MessageHeader *payload;
236 /* Connection closed */
240 switch (ntohs (msg->type))
242 case GNUNET_MESSAGE_TYPE_DV_CONNECT:
243 if (ntohs (msg->size) != sizeof (struct GNUNET_DV_ConnectMessage))
249 cm = (const struct GNUNET_DV_ConnectMessage *) msg;
250 sh->connect_cb (sh->cls,
252 ntohl (cm->distance));
254 case GNUNET_MESSAGE_TYPE_DV_DISCONNECT:
255 if (ntohs (msg->size) != sizeof (struct GNUNET_DV_DisconnectMessage))
261 dm = (const struct GNUNET_DV_DisconnectMessage *) msg;
262 sh->disconnect_cb (sh->cls,
265 case GNUNET_MESSAGE_TYPE_DV_RECV:
266 if (ntohs (msg->size) < sizeof (struct GNUNET_DV_ReceivedMessage) + sizeof (struct GNUNET_MessageHeader))
272 rm = (const struct GNUNET_DV_ReceivedMessage *) msg;
273 payload = (const struct GNUNET_MessageHeader *) &rm[1];
274 if (ntohs (msg->size) != sizeof (struct GNUNET_DV_ReceivedMessage) + ntohs (payload->size))
280 sh->message_cb (sh->cls,
282 ntohl (rm->distance),
289 GNUNET_CLIENT_receive (sh->client,
290 &handle_message_receipt, sh,
291 GNUNET_TIME_UNIT_FOREVER_REL);
296 * Transmit the start message to the DV service.
298 * @param cls the 'struct GNUNET_DV_ServiceHandle'
299 * @param size number of bytes available in buf
300 * @param buf where to copy the message
301 * @return number of bytes written to buf
304 transmit_start (void *cls,
308 struct GNUNET_DV_ServiceHandle *sh = cls;
309 struct GNUNET_MessageHeader start_message;
318 GNUNET_assert (size >= sizeof (start_message));
319 start_message.size = htons (sizeof (struct GNUNET_MessageHeader));
320 start_message.type = htons (GNUNET_MESSAGE_TYPE_DV_START);
321 memcpy (buf, &start_message, sizeof (start_message));
322 GNUNET_CLIENT_receive (sh->client,
323 &handle_message_receipt, sh,
324 GNUNET_TIME_UNIT_FOREVER_REL);
326 return sizeof (start_message);
331 * We got disconnected from the service and thus all of the
332 * pending send callbacks will never be confirmed. Clean up.
334 * @param cls the 'struct GNUNET_DV_ServiceHandle'
335 * @param key a peer identity
336 * @param value a 'struct GNUNET_DV_TransmitHandle' to clean up
337 * @return GNUNET_OK (continue to iterate)
340 cleanup_send_cb (void *cls,
341 const struct GNUNET_HashCode *key,
344 struct GNUNET_DV_ServiceHandle *sh = cls;
345 struct GNUNET_DV_TransmitHandle *th = value;
347 GNUNET_assert (GNUNET_YES ==
348 GNUNET_CONTAINER_multihashmap_remove (sh->send_callbacks,
351 th->cb (th->cb_cls, GNUNET_SYSERR);
358 * Disconnect and then reconnect to the DV service.
360 * @param sh service handle
363 reconnect (struct GNUNET_DV_ServiceHandle *sh)
367 GNUNET_CLIENT_notify_transmit_ready_cancel (sh->th);
370 if (NULL != sh->client)
372 GNUNET_CLIENT_disconnect (sh->client);
375 GNUNET_CONTAINER_multihashmap_iterate (sh->send_callbacks,
378 sh->client = GNUNET_CLIENT_connect ("dv", sh->cfg);
379 if (NULL == sh->client)
384 sh->th = GNUNET_CLIENT_notify_transmit_ready (sh->client,
385 sizeof (struct GNUNET_MessageHeader),
386 GNUNET_TIME_UNIT_FOREVER_REL,
394 * Connect to the DV service.
396 * @param cfg configuration
397 * @param cls closure for callbacks
398 * @param connect_cb function to call on connects
399 * @param disconnect_cb function to call on disconnects
400 * @param message_cb function to call if we receive messages
401 * @return handle to access the service
403 struct GNUNET_DV_ServiceHandle *
404 GNUNET_DV_service_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
406 GNUNET_DV_ConnectCallback connect_cb,
407 GNUNET_DV_DisconnectCallback disconnect_cb,
408 GNUNET_DV_MessageReceivedCallback message_cb)
410 struct GNUNET_DV_ServiceHandle *sh;
412 sh = GNUNET_malloc (sizeof (struct GNUNET_DV_ServiceHandle));
415 sh->connect_cb = connect_cb;
416 sh->disconnect_cb = disconnect_cb;
417 sh->message_cb = message_cb;
418 sh->send_callbacks = GNUNET_CONTAINER_multihashmap_create (128, GNUNET_YES);
425 * Disconnect from DV service.
427 * @param sh service handle
430 GNUNET_DV_service_disconnect (struct GNUNET_DV_ServiceHandle *sh)
432 struct GNUNET_DV_TransmitHandle *pos;
438 GNUNET_CLIENT_notify_transmit_ready_cancel (sh->th);
441 while (NULL != (pos = sh->th_head))
443 GNUNET_CONTAINER_DLL_remove (sh->th_head,
448 if (NULL != sh->client)
450 GNUNET_CLIENT_disconnect (sh->client);
453 GNUNET_CONTAINER_multihashmap_iterate (sh->send_callbacks,
456 GNUNET_CONTAINER_multihashmap_destroy (sh->send_callbacks);
462 * Send a message via DV service.
464 * @param sh service handle
465 * @param target intended recpient
466 * @param msg message payload
467 * @param cb function to invoke when done
468 * @param cb_cls closure for 'cb'
469 * @return handle to cancel the operation
471 struct GNUNET_DV_TransmitHandle *
472 GNUNET_DV_send (struct GNUNET_DV_ServiceHandle *sh,
473 const struct GNUNET_PeerIdentity *target,
474 const struct GNUNET_MessageHeader *msg,
475 GNUNET_DV_MessageSentCallback cb,
478 struct GNUNET_DV_TransmitHandle *th;
479 struct GNUNET_DV_SendMessage *sm;
481 if (ntohs (msg->size) + sizeof (struct GNUNET_DV_SendMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
486 th = GNUNET_malloc (sizeof (struct GNUNET_DV_TransmitHandle) +
487 sizeof (struct GNUNET_DV_SendMessage) +
490 th->target = *target;
493 th->msg = (const struct GNUNET_MessageHeader *) &th[1];
494 sm = (struct GNUNET_DV_SendMessage *) &th[1];
495 sm->header.type = htons (GNUNET_MESSAGE_TYPE_DV_SEND);
496 sm->header.size = htons (sizeof (struct GNUNET_DV_SendMessage) +
498 /* use memcpy here as 'target' may not be sufficiently aligned */
499 memcpy (&sm->target, target, sizeof (struct GNUNET_PeerIdentity));
500 memcpy (&sm[1], msg, ntohs (msg->size));
501 GNUNET_CONTAINER_DLL_insert (sh->th_head,
510 * Abort send operation (naturally, the message may have
511 * already been transmitted; this only stops the 'cb'
512 * from being called again).
514 * @param th send operation to cancel
517 GNUNET_DV_send_cancel (struct GNUNET_DV_TransmitHandle *th)
519 struct GNUNET_DV_ServiceHandle *sh = th->sh;
522 ret = GNUNET_CONTAINER_multihashmap_remove (sh->send_callbacks,
523 &th->target.hashPubKey,
525 if (GNUNET_YES != ret)
526 GNUNET_CONTAINER_DLL_remove (sh->th_head,
533 /* end of dv_api.c */