GNUnet  0.10.x
gnunet-service-fs_cadet_client.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2012, 2013 GNUnet e.V.
4 
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your 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  Affero General Public License for more details.
14 
15  You should have received a copy of the GNU Affero General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19 */
20 
30 #include "platform.h"
31 #include "gnunet_constants.h"
32 #include "gnunet_util_lib.h"
33 #include "gnunet_cadet_service.h"
34 #include "gnunet_protocols.h"
35 #include "gnunet_applications.h"
36 #include "gnunet-service-fs.h"
39 
40 
44 #define CLIENT_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
45 
46 
50 struct CadetHandle;
51 
52 
57 {
58 
63 
68 
72  struct CadetHandle *mh;
73 
78 
82  void *proc_cls;
83 
88 
93 
99 };
100 
101 
106 {
111 
116 
122 
127 
131  struct GNUNET_PeerIdentity target;
132 
139 
146 
147 };
148 
149 
154 
160 
161 
162 /* ********************* client-side code ************************* */
163 
164 
170 static void
171 transmit_pending (void *cls);
172 
173 
183 static int
184 move_to_pending (void *cls,
185  const struct GNUNET_HashCode *key,
186  void *value)
187 {
188  struct CadetHandle *mh = cls;
189  struct GSF_CadetRequest *sr = value;
190 
193  key,
194  value));
196  mh->pending_tail,
197  sr);
199  return GNUNET_YES;
200 }
201 
202 
211 static int
212 check_reply (void *cls,
213  const struct CadetReplyMessage *srm)
214 {
215  /* We check later... */
216  return GNUNET_OK;
217 }
218 
219 
225 static void
226 reset_cadet_task (void *cls);
227 
228 
235 static void
237 {
238  if (NULL != mh->reset_task)
241  mh);
242 }
243 
244 
249 {
250 
254  const void *data;
255 
260 
264  size_t data_size;
265 
270 
274  int found;
275 };
276 
277 
287 static int
288 process_reply (void *cls,
289  const struct GNUNET_HashCode *key,
290  void *value)
291 {
292  struct HandleReplyClosure *hrc = cls;
293  struct GSF_CadetRequest *sr = value;
294 
295  sr->proc (sr->proc_cls,
296  hrc->type,
297  hrc->expiration,
298  hrc->data_size,
299  hrc->data);
300  sr->proc = NULL;
302  hrc->found = GNUNET_YES;
303  return GNUNET_YES;
304 }
305 
306 
317 static int
319  const struct GNUNET_HashCode *key,
320  void *value)
321 {
322  struct GSF_CadetRequest *sr = value;
323 
325  return GNUNET_YES;
326 }
327 
328 
336 static void
337 handle_reply (void *cls,
338  const struct CadetReplyMessage *srm)
339 {
340  struct CadetHandle *mh = cls;
341  struct HandleReplyClosure hrc;
342  uint16_t msize;
343  enum GNUNET_BLOCK_Type type;
344  struct GNUNET_HashCode query;
345 
346  msize = ntohs (srm->header.size) - sizeof (struct CadetReplyMessage);
347  type = (enum GNUNET_BLOCK_Type) ntohl (srm->type);
348  if (GNUNET_YES !=
350  type,
351  &srm[1],
352  msize,
353  &query))
354  {
355  GNUNET_break_op (0);
357  "Received bogus reply of type %u with %u bytes via cadet from peer %s\n",
358  type,
359  msize,
360  GNUNET_i2s (&mh->target));
361  reset_cadet_async (mh);
362  return;
363  }
365  "Received reply `%s' via cadet from peer %s\n",
366  GNUNET_h2s (&query),
367  GNUNET_i2s (&mh->target));
370  gettext_noop ("# replies received via cadet"), 1,
371  GNUNET_NO);
372  hrc.data = &srm[1];
373  hrc.data_size = msize;
375  hrc.type = type;
376  hrc.found = GNUNET_NO;
378  &query,
379  &process_reply,
380  &hrc);
381  if (GNUNET_NO == hrc.found)
382  {
384  gettext_noop ("# replies received via cadet dropped"), 1,
385  GNUNET_NO);
386  }
387 }
388 
389 
397 static void
398 disconnect_cb (void *cls,
399  const struct GNUNET_CADET_Channel *channel)
400 {
401  struct CadetHandle *mh = cls;
402  struct GSF_CadetRequest *sr;
403 
404  if (NULL == mh->channel)
405  return; /* being destroyed elsewhere */
406  GNUNET_assert (channel == mh->channel);
407  mh->channel = NULL;
408  while (NULL != (sr = mh->pending_head))
410  /* first remove `mh` from the `cadet_map`, so that if the
411  callback from `free_waiting_entry()` happens to re-issue
412  the request, we don't immediately have it back in the
413  `waiting_map`. */
416  &mh->target,
417  mh));
420  mh);
421  if (NULL != mh->timeout_task)
423  if (NULL != mh->reset_task)
425  GNUNET_assert (0 ==
428  GNUNET_free (mh);
429 }
430 
431 
446 static void
447 window_change_cb (void *cls,
448  const struct GNUNET_CADET_Channel *channel,
449  int window_size)
450 {
451  /* FIXME: for flow control, implement? */
452 #if 0
453  /* Something like this instead of the GNUNET_MQ_notify_sent() in
454  transmit_pending() might be good (once the window change CB works...) */
455  if (0 < window_size) /* test needed? */
457 #endif
458 }
459 
460 
466 static void
468 {
470  "Resetting cadet channel to %s\n",
471  GNUNET_i2s (&mh->target));
472  if (NULL != mh->channel)
473  {
475  mh->channel = NULL;
476  }
479  mh);
480  {
481  struct GNUNET_MQ_MessageHandler handlers[] = {
482  GNUNET_MQ_hd_var_size (reply,
484  struct CadetReplyMessage,
485  mh),
487  };
488  struct GNUNET_HashCode port;
489 
492  &port);
493  mh->channel = GNUNET_CADET_channel_create (cadet_handle,
494  mh,
495  &mh->target,
496  &port,
499  &disconnect_cb,
500  handlers);
501  }
502  transmit_pending (mh);
503 }
504 
505 
511 static void
512 cadet_timeout (void *cls)
513 {
514  struct CadetHandle *mh = cls;
515  struct GNUNET_CADET_Channel *tun;
516 
518  "Timeout on cadet channel to %s\n",
519  GNUNET_i2s (&mh->target));
520  mh->timeout_task = NULL;
521  tun = mh->channel;
522  mh->channel = NULL;
523  if (NULL != tun)
525 }
526 
527 
533 static void
534 reset_cadet_task (void *cls)
535 {
536  struct CadetHandle *mh = cls;
537 
538  mh->reset_task = NULL;
539  reset_cadet (mh);
540 }
541 
542 
548 static void
549 transmit_pending (void *cls)
550 {
551  struct CadetHandle *mh = cls;
553  struct GSF_CadetRequest *sr;
554  struct GNUNET_MQ_Envelope *env;
555  struct CadetQueryMessage *sqm;
556 
557  if ( (0 != GNUNET_MQ_get_length (mq)) ||
558  (NULL == (sr = mh->pending_head)) )
559  return;
561  mh->pending_tail,
562  sr);
565  &sr->query,
566  sr,
570  "Sending query for %s via cadet to %s\n",
571  GNUNET_h2s (&sr->query),
572  GNUNET_i2s (&mh->target));
573  env = GNUNET_MQ_msg (sqm,
575  sqm->type = htonl (sr->type);
576  sqm->query = sr->query;
579  mh);
580  GNUNET_MQ_send (mq,
581  env);
582 }
583 
584 
590 static struct CadetHandle *
592 {
593  struct CadetHandle *mh;
594 
595  mh = GNUNET_CONTAINER_multipeermap_get (cadet_map,
596  target);
597  if (NULL != mh)
598  {
599  if (NULL != mh->timeout_task)
600  {
602  mh->timeout_task = NULL;
603  }
604  return mh;
605  }
607  "Creating cadet channel to %s\n",
608  GNUNET_i2s (target));
609  mh = GNUNET_new (struct CadetHandle);
612  mh);
614  mh->target = *target;
617  &mh->target,
618  mh,
620  {
621  struct GNUNET_MQ_MessageHandler handlers[] = {
622  GNUNET_MQ_hd_var_size (reply,
624  struct CadetReplyMessage,
625  mh),
627  };
628  struct GNUNET_HashCode port;
629 
632  &port);
633  mh->channel = GNUNET_CADET_channel_create (cadet_handle,
634  mh,
635  &mh->target,
636  &port,
639  &disconnect_cb,
640  handlers);
641  }
642  return mh;
643 }
644 
645 
656 struct GSF_CadetRequest *
657 GSF_cadet_query (const struct GNUNET_PeerIdentity *target,
658  const struct GNUNET_HashCode *query,
659  enum GNUNET_BLOCK_Type type,
661  void *proc_cls)
662 {
663  struct CadetHandle *mh;
664  struct GSF_CadetRequest *sr;
665 
667  "Preparing to send query for %s via cadet to %s\n",
668  GNUNET_h2s (query),
669  GNUNET_i2s (target));
670  mh = get_cadet (target);
671  sr = GNUNET_new (struct GSF_CadetRequest);
672  sr->mh = mh;
673  sr->proc = proc;
674  sr->proc_cls = proc_cls;
675  sr->type = type;
676  sr->query = *query;
678  mh->pending_tail,
679  sr);
680  transmit_pending (mh);
681  return sr;
682 }
683 
684 
691 void
693 {
694  struct CadetHandle *mh = sr->mh;
696 
697  p = sr->proc;
698  sr->proc = NULL;
699  if (NULL != p)
700  {
701  /* signal failure / cancellation to callback */
704  0, NULL);
705  }
707  "Cancelled query for %s via cadet to %s\n",
708  GNUNET_h2s (&sr->query),
709  GNUNET_i2s (&sr->mh->target));
710  if (GNUNET_YES == sr->was_transmitted)
713  &sr->query,
714  sr));
715  else
717  mh->pending_tail,
718  sr);
719  GNUNET_free (sr);
721  (NULL == mh->pending_head) )
723  &cadet_timeout,
724  mh);
725 }
726 
727 
736 int
738  const struct GNUNET_PeerIdentity *key,
739  void *value)
740 {
741  struct CadetHandle *mh = value;
742 
744  "Timeout on cadet channel to %s\n",
745  GNUNET_i2s (&mh->target));
746  if (NULL != mh->channel)
747  {
748  struct GNUNET_CADET_Channel *channel = mh->channel;
749 
750  mh->channel = NULL;
752  }
753  if (NULL != mh->reset_task)
754  {
756  mh->reset_task = NULL;
757  }
758  return GNUNET_YES;
759 }
760 
761 
762 
763 /* end of gnunet-service-fs_cadet_client.c */
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
static void window_change_cb(void *cls, const struct GNUNET_CADET_Channel *channel, int window_size)
Function called whenever an MQ-channel&#39;s transmission window size changes.
#define GNUNET_MESSAGE_TYPE_FS_CADET_REPLY
P2P answer for content (one FS to another via a cadet).
struct GNUNET_TIME_Absolute expiration
Expiration time for the block.
struct GNUNET_CONTAINER_MultiPeerMap * cadet_map
Map from peer identities to &#39;struct CadetHandles&#39; with cadet channels to those peers.
Query from one peer, asking the other for CHK-data.
int found
Did we have a matching query?
static char * expiration
Credential TTL.
static int check_reply(void *cls, const struct CadetReplyMessage *srm)
Functions with this signature are called whenever a complete reply is received.
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_ntoh(struct GNUNET_TIME_AbsoluteNBO a)
Convert absolute time from network byte order.
Definition: time.c:670
#define GNUNET_TIME_UNIT_ZERO_ABS
Absolute time zero.
struct GSF_CadetRequest * GSF_cadet_query(const struct GNUNET_PeerIdentity *target, const struct GNUNET_HashCode *query, enum GNUNET_BLOCK_Type type, GSF_CadetReplyProcessor proc, void *proc_cls)
Look for a block by directly contacting a particular peer.
unsigned int GNUNET_CONTAINER_multihashmap_size(const struct GNUNET_CONTAINER_MultiHashMap *map)
Get the number of key-value pairs in the map.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
Any type of block, used as a wildcard when searching.
Opaque handle to the service.
Definition: cadet_api.c:38
GNUNET_BLOCK_Type
Blocks in the datastore and the datacache must have a unique type.
static void disconnect_cb(void *cls, const struct GNUNET_CADET_Channel *channel)
Function called by cadet when a client disconnects.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
Handle for a cadet to another peer.
#define GNUNET_TIME_UNIT_SECONDS
One second.
struct GNUNET_MessageHeader header
Type is GNUNET_MESSAGE_TYPE_FS_CADET_REPLY.
Enable channel reliability, lost messages will be retransmitted.
static int process_reply(void *cls, const struct GNUNET_HashCode *key, void *value)
Iterator called on each entry in a waiting map to process a result.
#define GNUNET_MQ_msg(mvar, type)
Allocate a GNUNET_MQ_Envelope.
Definition: gnunet_mq_lib.h:67
static int move_to_pending(void *cls, const struct GNUNET_HashCode *key, void *value)
Iterator called on each entry in a waiting map to move it back to the pending list.
uint32_t type
Block type must be DBLOCK or IBLOCK.
int GNUNET_CONTAINER_multihashmap_iterate(struct GNUNET_CONTAINER_MultiHashMap *map, GNUNET_CONTAINER_HashMapIterator it, void *it_cls)
Iterate over all entries in the map.
struct GNUNET_STATISTICS_Handle * GSF_stats
Handle for reporting statistics.
int GNUNET_CONTAINER_multipeermap_remove(struct GNUNET_CONTAINER_MultiPeerMap *map, const struct GNUNET_PeerIdentity *key, const void *value)
Remove the given key-value pair from the map.
#define GNUNET_NO
Definition: gnunet_common.h:81
shared data structures of gnunet-service-fs.c
Opaque handle to a channel.
Definition: cadet_api.c:80
const char * GNUNET_h2s(const struct GNUNET_HashCode *hc)
Convert a hash value to a string (for printing debug messages).
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:78
#define GNUNET_new(type)
Allocate a struct or union of the given type.
static void handle_reply(void *cls, const struct CadetReplyMessage *srm)
Functions with this signature are called whenever a complete reply is received.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format...
void GNUNET_STATISTICS_update(struct GNUNET_STATISTICS_Handle *handle, const char *name, int64_t delta, int make_persistent)
Set statistic value for the peer.
Internal representation of the hash map.
struct GNUNET_HashCode query
Query to transmit to the other peer.
int GNUNET_BLOCK_get_key(struct GNUNET_BLOCK_Context *ctx, enum GNUNET_BLOCK_Type type, const void *block, size_t block_size, struct GNUNET_HashCode *key)
Function called to obtain the key for a block.
Definition: block.c:379
static void reset_cadet_async(struct CadetHandle *mh)
We had a serious error, tear down and re-create cadet from scratch, but do so asynchronously.
const void * data
Reply payload.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition: scheduler.c:1246
#define CLIENT_RETRY_TIMEOUT
After how long do we reset connections without replies?
static struct GNUNET_OS_Process * p
Helper process we started.
Definition: gnunet-qr.c:59
struct GNUNET_HashCode query
Query hash from CHK (hash of encrypted block).
void GNUNET_MQ_notify_sent(struct GNUNET_MQ_Envelope *ev, GNUNET_SCHEDULER_TaskCallback cb, void *cb_cls)
Call a callback once the envelope has been sent, that is, sending it can not be canceled anymore...
Definition: mq.c:774
static char * value
Value of the record to add/remove.
int was_transmitted
Did we transmit this request already? GNUNET_YES if we are in the &#39;waiting_map&#39;, GNUNET_NO if we are ...
#define GNUNET_MQ_hd_var_size(name, code, str, ctx)
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
void GNUNET_CRYPTO_hash(const void *block, size_t size, struct GNUNET_HashCode *ret)
Compute hash of a given block.
Definition: crypto_hash.c:44
unsigned int GNUNET_MQ_get_length(struct GNUNET_MQ_Handle *mq)
Obtain the current length of the message queue.
Definition: mq.c:335
void GNUNET_CONTAINER_multihashmap_destroy(struct GNUNET_CONTAINER_MultiHashMap *map)
Destroy a hash map.
struct GSF_CadetRequest * next
DLL.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition: scheduler.c:1273
struct GSF_CadetRequest * prev
DLL.
struct GNUNET_BLOCK_Context * GSF_block_ctx
Our block context.
static void reset_cadet_task(void *cls)
Task called when it is time to reset an cadet.
non-anonymous file-transfer
int GNUNET_CONTAINER_multihashmap_remove(struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key, const void *value)
Remove the given key-value pair from the map.
void * proc_cls
Closure for proc.
Closure for handle_reply().
Internal representation of the hash map.
struct GNUNET_PeerIdentity target
Which peer does this cadet go to?
A 512-bit hashcode.
Message handler for a specific message type.
struct GNUNET_SCHEDULER_Task * timeout_task
Task to kill inactive cadets (we keep them around for a few seconds to give the application a chance ...
struct GNUNET_SCHEDULER_Task * reset_task
Task to reset cadets that had errors (asynchronously, as we may not be able to do it immediately duri...
There must only be one value per key; storing a value should fail if a value under the same key alrea...
Handle for a request that is going out via cadet API.
struct GNUNET_HashCode key
The key used in the DHT.
struct GNUNET_MQ_Envelope * env
Definition: 005.c:1
struct GNUNET_TIME_AbsoluteNBO expiration
Expiration time for the block.
indexing for the file-sharing service
int GNUNET_CONTAINER_multihashmap_put(struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key, void *value, enum GNUNET_CONTAINER_MultiHashMapOption opt)
Store a key-value pair in the map.
GSF_CadetReplyProcessor proc
Function to call with the result.
Allow multiple values with the same key.
Handle to a message queue.
Definition: mq.c:85
int GNUNET_CONTAINER_multipeermap_put(struct GNUNET_CONTAINER_MultiPeerMap *map, const struct GNUNET_PeerIdentity *key, void *value, enum GNUNET_CONTAINER_MultiHashMapOption opt)
Store a key-value pair in the map.
The identity of the host (wraps the signing key of the peer).
void GNUNET_CADET_receive_done(struct GNUNET_CADET_Channel *channel)
Send an ack on the channel to confirm the processing of a message.
Definition: cadet_api.c:973
struct GNUNET_CADET_Channel * channel
Channel to the other peer.
struct GSF_CadetRequest * pending_head
Head of DLL of pending requests on this cadet.
struct GSF_CadetRequest * pending_tail
Tail of DLL of pending requests on this cadet.
static void reset_cadet(struct CadetHandle *mh)
We had a serious error, tear down and re-create cadet from scratch.
int GNUNET_CONTAINER_multihashmap_get_multiple(struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key, GNUNET_CONTAINER_HashMapIterator it, void *it_cls)
Iterate over all entries in the map that match a particular key.
void * GNUNET_CONTAINER_multipeermap_get(const struct GNUNET_CONTAINER_MultiPeerMap *map, const struct GNUNET_PeerIdentity *key)
Given a key find a value in the map matching the key.
struct GNUNET_MQ_Handle * mq
Definition: 003.c:5
#define GNUNET_MESSAGE_TYPE_FS_CADET_QUERY
P2P request for content (one FS to another via a cadet).
#define GNUNET_log(kind,...)
Entry in list of pending tasks.
Definition: scheduler.c:134
static void cadet_timeout(void *cls)
Task called when it is time to destroy an inactive cadet channel.
static int free_waiting_entry(void *cls, const struct GNUNET_HashCode *key, void *value)
Iterator called on each entry in a waiting map to call the &#39;proc&#39; continuation and release associated...
struct GNUNET_CONTAINER_MultiHashMap * GNUNET_CONTAINER_multihashmap_create(unsigned int len, int do_not_copy_keys)
Create a multi hash map.
#define GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER
Transfer of blocks for non-anonymmous file-sharing.
Time for absolute times used by GNUnet, in microseconds.
#define GNUNET_YES
Definition: gnunet_common.h:80
void GNUNET_MQ_send(struct GNUNET_MQ_Handle *mq, struct GNUNET_MQ_Envelope *ev)
Send a message with the given message queue.
Definition: mq.c:353
uint32_t type
Block type must be DBLOCK or IBLOCK.
int GSF_cadet_release_clients(void *cls, const struct GNUNET_PeerIdentity *key, void *value)
Function called on each active cadets to shut them down.
static void transmit_pending(void *cls)
Transmit pending requests via the cadet.
struct GNUNET_CADET_Handle * cadet_handle
Cadet channel for creating outbound channels.
enum GNUNET_BLOCK_Type type
Type of the block.
struct CadetHandle * mh
Which cadet is this request associated with?
size_t data_size
Number of bytes in data.
Reply to a CadetQueryMessage.
void GNUNET_CADET_channel_destroy(struct GNUNET_CADET_Channel *channel)
Destroy an existing channel.
Definition: cadet_api.c:911
const char * GNUNET_i2s(const struct GNUNET_PeerIdentity *pid)
Convert a peer identity to a string (for printing debug messages).
struct GNUNET_CONTAINER_MultiHashMap * waiting_map
Map from query to struct GSF_CadetRequests waiting for a reply.
enum GNUNET_BLOCK_Type type
Desired type for the reply.
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
void(* GSF_CadetReplyProcessor)(void *cls, enum GNUNET_BLOCK_Type type, struct GNUNET_TIME_Absolute expiration, size_t data_size, const void *data)
Function called with a reply from the cadet.
void GSF_cadet_query_cancel(struct GSF_CadetRequest *sr)
Cancel an active request; must not be called after &#39;proc&#39; was calld.
#define GNUNET_free(ptr)
Wrapper around free.
static struct CadetHandle * get_cadet(const struct GNUNET_PeerIdentity *target)
Get (or create) a cadet to talk to the given peer.
struct GNUNET_CADET_Channel * GNUNET_CADET_channel_create(struct GNUNET_CADET_Handle *h, void *channel_cls, const struct GNUNET_PeerIdentity *destination, const struct GNUNET_HashCode *port, enum GNUNET_CADET_ChannelOption options, GNUNET_CADET_WindowSizeEventHandler window_changes, GNUNET_CADET_DisconnectEventHandler disconnects, const struct GNUNET_MQ_MessageHandler *handlers)
Create a new channel towards a remote peer.
Definition: cadet_api.c:1088
#define gettext_noop(String)
Definition: gettext.h:69
struct GNUNET_MQ_Handle * GNUNET_CADET_get_mq(const struct GNUNET_CADET_Channel *channel)
Obtain the message queue for a connected peer.
Definition: cadet_api.c:1142
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:965