3 This file is part of GNUnet.
4 Copyright (C) 2001-2017 GNUnet e.V.
6 GNUnet is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; either version 3, or (at your
9 option) any later version.
11 GNUnet is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNUnet; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
23 * @file cadet/gnunet-service-cadet-new_peer.c
24 * @brief Information we track per peer.
25 * @author Bartlomiej Polot
26 * @author Christian Grothoff
29 * - optimize stopping/restarting DHT search to situations
30 * where we actually need it (i.e. not if we have a direct connection,
31 * or if we already have plenty of good short ones, or maybe even
32 * to take a break if we have some connections and have searched a lot (?))
33 * - optimize MQM ready scans (O(n) -> O(1))
36 #include "gnunet_util_lib.h"
37 #include "gnunet_signatures.h"
38 #include "gnunet_transport_service.h"
39 #include "gnunet_ats_service.h"
40 #include "gnunet_core_service.h"
41 #include "gnunet_statistics_service.h"
42 #include "cadet_protocol.h"
43 #include "cadet_path.h"
44 #include "gnunet-service-cadet-new.h"
45 #include "gnunet-service-cadet-new_connection.h"
46 #include "gnunet-service-cadet-new_dht.h"
47 #include "gnunet-service-cadet-new_peer.h"
48 #include "gnunet-service-cadet-new_paths.h"
49 #include "gnunet-service-cadet-new_tunnels.h"
52 * How long do we wait until tearing down an idle peer?
54 #define IDLE_PEER_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
57 * How long do we keep paths around if we no longer care about the peer?
59 #define IDLE_PATH_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2)
65 * Data structure used to track whom we have to notify about changes
66 * to our message queue.
68 struct GCP_MessageQueueManager
74 struct GCP_MessageQueueManager *next;
79 struct GCP_MessageQueueManager *prev;
82 * Function to call with updated message queue object.
84 GCP_MessageQueueNotificationCallback cb;
92 * The peer this is for.
97 * Envelope this manager would like to transmit once it is its turn.
99 struct GNUNET_MQ_Envelope *env;
105 * Struct containing all information regarding a given peer
112 struct GNUNET_PeerIdentity pid;
115 * Last time we heard from this peer
117 struct GNUNET_TIME_Absolute last_contact;
120 * Array of DLLs of paths traversing the peer, organized by the
121 * offset of the peer on the larger path.
123 struct CadetPeerPathEntry **path_heads;
126 * Array of DLL of paths traversing the peer, organized by the
127 * offset of the peer on the larger path.
129 struct CadetPeerPathEntry **path_tails;
132 * Notifications to call when @e core_mq changes.
134 struct GCP_MessageQueueManager *mqm_head;
137 * Notifications to call when @e core_mq changes.
139 struct GCP_MessageQueueManager *mqm_tail;
142 * MIN-heap of paths owned by this peer (they also end at this
143 * peer). Ordered by desirability.
145 struct GNUNET_CONTAINER_Heap *path_heap;
148 * Handle to stop the DHT search for paths to this peer
150 struct GCD_search_handle *search_h;
153 * Task to stop the DHT search for paths to this peer
155 struct GNUNET_SCHEDULER_Task *search_delayedXXX;
158 * Task to destroy this entry.
160 struct GNUNET_SCHEDULER_Task *destroy_task;
163 * Tunnel to this peer, if any.
165 struct CadetTunnel *t;
168 * Connections that go through this peer; indexed by tid.
170 struct GNUNET_CONTAINER_MultiShortmap *connections;
173 * Handle for core transmissions.
175 struct GNUNET_MQ_Handle *core_mq;
178 * Hello message of the peer.
180 struct GNUNET_HELLO_Message *hello;
183 * Handle to us offering the HELLO to the transport.
185 struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer;
188 * Handle to our ATS request asking ATS to suggest an address
189 * to TRANSPORT for this peer (to establish a direct link).
191 struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion;
194 * How many messages are in the queue to this peer.
196 unsigned int queue_n;
199 * How many paths do we have to this peer (in all @e path_heads DLLs combined).
201 unsigned int num_paths;
204 * Number of message queue managers of this peer that have a message in waiting.
206 * Used to quickly see if we need to bother scanning the @e msm_head DLL.
207 * TODO: could be replaced by another DLL that would then allow us to avoid
208 * the O(n)-scan of the DLL for ready entries!
210 unsigned int mqm_ready_counter;
213 * Current length of the @e path_heads and @path_tails arrays.
214 * The arrays should be grown as needed.
216 unsigned int path_dll_length;
222 * Get the static string for a peer ID.
226 * @return Static string for it's ID.
229 GCP_2s (const struct CadetPeer *peer)
233 return GNUNET_i2s (&peer->pid);
238 * This peer is no longer be needed, clean it up now.
240 * @param cls peer to clean up
243 destroy_peer (void *cls)
245 struct CadetPeer *cp = cls;
247 cp->destroy_task = NULL;
248 GNUNET_assert (NULL == cp->t);
249 GNUNET_assert (NULL == cp->core_mq);
250 GNUNET_assert (0 == cp->path_dll_length);
251 GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections));
252 GNUNET_assert (GNUNET_YES ==
253 GNUNET_CONTAINER_multipeermap_remove (peers,
256 GNUNET_free_non_null (cp->path_heads);
257 GNUNET_free_non_null (cp->path_tails);
258 cp->path_dll_length = 0;
259 if (NULL != cp->search_h)
261 GCD_search_stop (cp->search_h);
264 /* FIXME: clean up search_delayedXXX! */
266 if (NULL != cp->hello_offer)
268 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
269 cp->hello_offer = NULL;
271 if (NULL != cp->connectivity_suggestion)
273 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
274 cp->connectivity_suggestion = NULL;
276 GNUNET_CONTAINER_multishortmap_destroy (cp->connections);
277 GNUNET_CONTAINER_heap_destroy (cp->path_heap);
278 GNUNET_free_non_null (cp->hello);
279 /* Peer should not be freed if paths exist; if there are no paths,
280 there ought to be no connections, and without connections, no
281 notifications. Thus we can assert that mqm_head is empty at this
283 GNUNET_assert (NULL == cp->mqm_head);
289 * Set the message queue to @a mq for peer @a cp and notify watchers.
291 * @param cp peer to modify
292 * @param mq message queue to set (can be NULL)
295 GCP_set_mq (struct CadetPeer *cp,
296 struct GNUNET_MQ_Handle *mq)
300 for (struct GCP_MessageQueueManager *mqm = cp->mqm_head;
306 if (NULL != mqm->env)
308 GNUNET_MQ_discard (mqm->env);
310 mqm->cb (mqm->cb_cls,
315 mqm->cb (mqm->cb_cls,
321 GNUNET_assert (NULL == mqm->env);
322 mqm->cb (mqm->cb_cls,
330 * Transmit current envelope from this @a mqm.
332 * @param mqm mqm to transmit message for now
335 mqm_execute (struct GCP_MessageQueueManager *mqm)
337 struct CadetPeer *cp = mqm->cp;
339 /* Move entry to the end of the DLL, to be fair. */
340 if (mqm != cp->mqm_tail)
342 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
345 GNUNET_CONTAINER_DLL_insert_tail (cp->mqm_head,
349 GNUNET_MQ_send (cp->core_mq,
352 cp->mqm_ready_counter--;
357 * Function called when CORE took one of the messages from
358 * a message queue manager and transmitted it.
360 * @param cls the `struct CadetPeeer` where we made progress
363 mqm_send_done (void *cls)
365 struct CadetPeer *cp = cls;
367 if (0 == cp->mqm_ready_counter)
368 return; /* nothing to do */
369 for (struct GCP_MessageQueueManager *mqm = cp->mqm_head;
373 if (NULL == mqm->env)
382 * Send the message in @a env to @a cp.
384 * @param mqm the message queue manager to use for transmission
385 * @param env envelope with the message to send; must NOT
386 * yet have a #GNUNET_MQ_notify_sent() callback attached to it
389 GCP_send (struct GCP_MessageQueueManager *mqm,
390 struct GNUNET_MQ_Envelope *env)
392 struct CadetPeer *cp = mqm->cp;
394 GNUNET_assert (NULL != cp->core_mq);
395 GNUNET_assert (NULL == mqm->env);
396 GNUNET_MQ_notify_sent (env,
400 cp->mqm_ready_counter++;
401 if (0 != GNUNET_MQ_get_length (cp->core_mq))
408 * Function called to destroy a peer now.
411 * @param pid identity of the peer (unused)
412 * @param value the `struct CadetPeer` to clean up
413 * @return #GNUNET_OK (continue to iterate)
416 destroy_iterator_cb (void *cls,
417 const struct GNUNET_PeerIdentity *pid,
420 struct CadetPeer *cp = value;
422 if (NULL != cp->destroy_task)
424 GNUNET_SCHEDULER_cancel (cp->destroy_task);
425 cp->destroy_task = NULL;
433 * Clean up all entries about all peers.
434 * Must only be called after all tunnels, CORE-connections and
435 * connections are down.
438 GCP_destroy_all_peers ()
440 GNUNET_CONTAINER_multipeermap_iterate (peers,
441 &destroy_iterator_cb,
447 * This peer may no longer be needed, consider cleaning it up.
449 * @param cp peer to clean up
452 consider_peer_destroy (struct CadetPeer *cp);
456 * We really no longere care about a peer, stop hogging memory with paths to it.
457 * Afterwards, see if there is more to be cleaned up about this peer.
459 * @param cls a `struct CadetPeer`.
462 drop_paths (void *cls)
464 struct CadetPeer *cp = cls;
465 struct CadetPeerPath *path;
467 cp->destroy_task = NULL;
468 while (NULL != (path = GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
470 consider_peer_destroy (cp);
475 * This peer may no longer be needed, consider cleaning it up.
477 * @param cp peer to clean up
480 consider_peer_destroy (struct CadetPeer *cp)
482 struct GNUNET_TIME_Relative exp;
484 if (NULL != cp->destroy_task)
486 GNUNET_SCHEDULER_cancel (cp->destroy_task);
487 cp->destroy_task = NULL;
490 return; /* still relevant! */
491 if (NULL != cp->core_mq)
492 return; /* still relevant! */
493 if (0 != GNUNET_CONTAINER_multishortmap_size (cp->connections))
494 return; /* still relevant! */
495 if (0 < GNUNET_CONTAINER_heap_get_size (cp->path_heap))
497 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT,
502 if (0 < cp->path_dll_length)
503 return; /* still relevant! */
504 if (NULL != cp->hello)
506 /* relevant only until HELLO expires */
507 exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello));
508 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp,
513 cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
520 * Add an entry to the DLL of all of the paths that this peer is on.
522 * @param cp peer to modify
523 * @param entry an entry on a path
524 * @param off offset of this peer on the path
527 GCP_path_entry_add (struct CadetPeer *cp,
528 struct CadetPeerPathEntry *entry,
531 if (off >= cp->path_dll_length)
533 unsigned int len = cp->path_dll_length;
535 GNUNET_array_grow (cp->path_heads,
538 GNUNET_array_grow (cp->path_tails,
542 GNUNET_CONTAINER_DLL_insert (cp->path_heads[off],
547 /* If we have a tunnel to this peer, tell the tunnel that there is a
548 new path available. */
550 GCT_consider_path (cp->t,
557 * Remove an entry from the DLL of all of the paths that this peer is on.
559 * @param cp peer to modify
560 * @param entry an entry on a path
561 * @param off offset of this peer on the path
564 GCP_path_entry_remove (struct CadetPeer *cp,
565 struct CadetPeerPathEntry *entry,
568 GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
571 GNUNET_assert (0 < cp->num_paths);
577 * Try adding a @a path to this @a peer. If the peer already
578 * has plenty of paths, return NULL.
580 * @param cp peer to which the @a path leads to
581 * @param path a path looking for an owner; may not be fully initialized yet!
582 * @param off offset of @a cp in @a path
583 * @return NULL if this peer does not care to become a new owner,
584 * otherwise the node in the peer's path heap for the @a path.
586 struct GNUNET_CONTAINER_HeapNode *
587 GCP_attach_path (struct CadetPeer *cp,
588 struct CadetPeerPath *path,
591 GNUNET_CONTAINER_HeapCostType desirability;
592 struct CadetPeerPath *root;
593 GNUNET_CONTAINER_HeapCostType root_desirability;
594 struct GNUNET_CONTAINER_HeapNode *hn;
596 /* FIXME: desirability is not yet initialized; tricky! */
597 desirability = GCPP_get_desirability (path);
599 GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
604 root_desirability = 0;
607 if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) &&
608 (desirability < root_desirability) )
611 /* Yes, we'd like to add this path, add to our heap */
612 hn = GNUNET_CONTAINER_heap_insert (cp->path_heap,
616 /* Consider maybe dropping other paths because of the new one */
617 if (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
618 2 * DESIRED_CONNECTIONS_PER_TUNNEL)
620 /* Now we have way too many, drop least desirable UNLESS it is in use!
621 (Note that this intentionally keeps highly desireable, but currently
622 unused paths around in the hope that we might be able to switch, even
623 if the number of paths exceeds the threshold.) */
624 root = GNUNET_CONTAINER_heap_peek (cp->path_heap);
626 GCPP_get_connection (root,
628 GCPP_get_length (root) - 1))
630 /* Got plenty of paths to this destination, and this is a low-quality
631 one that we don't care, allow it to die. */
632 GNUNET_assert (root ==
633 GNUNET_CONTAINER_heap_remove_root (cp->path_heap));
642 * This peer can no longer own @a path as the path
643 * has been extended and a peer further down the line
644 * is now the new owner.
646 * @param cp old owner of the @a path
647 * @param path path where the ownership is lost
648 * @param hn note in @a cp's path heap that must be deleted
651 GCP_detach_path (struct CadetPeer *cp,
652 struct CadetPeerPath *path,
653 struct GNUNET_CONTAINER_HeapNode *hn)
655 GNUNET_assert (path ==
656 GNUNET_CONTAINER_heap_remove_node (hn));
661 * Add a @a connection to this @a cp.
663 * @param cp peer via which the @a connection goes
664 * @param cc the connection to add
667 GCP_add_connection (struct CadetPeer *cp,
668 struct CadetConnection *cc)
670 GNUNET_assert (GNUNET_OK ==
671 GNUNET_CONTAINER_multishortmap_put (cp->connections,
672 &GCC_get_id (cc)->connection_of_tunnel,
674 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
679 * Remove a @a connection that went via this @a cp.
681 * @param cp peer via which the @a connection went
682 * @param cc the connection to remove
685 GCP_remove_connection (struct CadetPeer *cp,
686 struct CadetConnection *cc)
688 GNUNET_assert (GNUNET_YES ==
689 GNUNET_CONTAINER_multishortmap_remove (cp->connections,
690 &GCC_get_id (cc)->connection_of_tunnel,
696 * This peer is now on more "active" duty, activate processes related to it.
698 * @param cp the more-active peer
701 consider_peer_activate (struct CadetPeer *cp)
705 if (NULL != cp->destroy_task)
707 /* It's active, do not destory! */
708 GNUNET_SCHEDULER_cancel (cp->destroy_task);
709 cp->destroy_task = NULL;
711 if ( (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections)) &&
714 /* We're just on a path or directly connected; don't bother too much */
715 if (NULL != cp->connectivity_suggestion)
717 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
718 cp->connectivity_suggestion = NULL;
720 if (NULL != cp->search_h)
722 GCD_search_stop (cp->search_h);
727 if (NULL == cp->core_mq)
729 /* Lacks direct connection, try to create one by querying the DHT */
730 if ( (NULL == cp->search_h) &&
731 (DESIRED_CONNECTIONS_PER_TUNNEL < cp->num_paths) )
733 = GCD_search (&cp->pid);
737 /* Have direct connection, stop DHT search if active */
738 if (NULL != cp->search_h)
740 GCD_search_stop (cp->search_h);
745 /* If we have a tunnel, our urge for connections is much bigger */
746 strength = (NULL != cp->t) ? 32 : 1;
747 if (NULL != cp->connectivity_suggestion)
748 GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
749 cp->connectivity_suggestion
750 = GNUNET_ATS_connectivity_suggest (ats_ch,
757 * Retrieve the CadetPeer stucture associated with the
758 * peer. Optionally create one and insert it in the appropriate
759 * structures if the peer is not known yet.
761 * @param peer_id Full identity of the peer.
762 * @param create #GNUNET_YES if a new peer should be created if unknown.
763 * #GNUNET_NO to return NULL if peer is unknown.
764 * @return Existing or newly created peer structure.
765 * NULL if unknown and not requested @a create
768 GCP_get (const struct GNUNET_PeerIdentity *peer_id,
771 struct CadetPeer *cp;
773 cp = GNUNET_CONTAINER_multipeermap_get (peers,
777 if (GNUNET_NO == create)
779 cp = GNUNET_new (struct CadetPeer);
781 cp->connections = GNUNET_CONTAINER_multishortmap_create (32,
783 cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
784 GNUNET_assert (GNUNET_YES ==
785 GNUNET_CONTAINER_multipeermap_put (peers,
788 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
794 * Obtain the peer identity for a `struct CadetPeer`.
796 * @param cp our peer handle
797 * @return the peer identity
799 const struct GNUNET_PeerIdentity *
800 GCP_get_id (struct CadetPeer *cp)
807 * Iterate over all known peers.
809 * @param iter Iterator.
810 * @param cls Closure for @c iter.
813 GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
816 GNUNET_CONTAINER_multipeermap_iterate (peers,
823 * Count the number of known paths toward the peer.
825 * @param peer Peer to get path info.
826 * @return Number of known paths.
829 GCP_count_paths (const struct CadetPeer *peer)
831 return peer->num_paths;
836 * Iterate over the paths to a peer.
838 * @param peer Peer to get path info.
839 * @param callback Function to call for every path.
840 * @param callback_cls Closure for @a callback.
841 * @return Number of iterated paths.
844 GCP_iterate_paths (struct CadetPeer *peer,
845 GCP_PathIterator callback,
848 unsigned int ret = 0;
850 for (unsigned int i=0;i<peer->path_dll_length;i++)
852 for (struct CadetPeerPathEntry *pe = peer->path_heads[i];
857 callback (callback_cls,
869 * Iterate over the paths to @a peer where
870 * @a peer is at distance @a dist from us.
872 * @param peer Peer to get path info.
873 * @param dist desired distance of @a peer to us on the path
874 * @param callback Function to call for every path.
875 * @param callback_cls Closure for @a callback.
876 * @return Number of iterated paths.
879 GCP_iterate_paths_at (struct CadetPeer *peer,
881 GCP_PathIterator callback,
884 unsigned int ret = 0;
886 if (dist<peer->path_dll_length)
888 for (struct CadetPeerPathEntry *pe = peer->path_heads[dist];
893 callback (callback_cls,
904 * Get the tunnel towards a peer.
906 * @param cp Peer to get from.
907 * @param create #GNUNET_YES to create a tunnel if we do not have one
908 * @return Tunnel towards peer.
911 GCP_get_tunnel (struct CadetPeer *cp,
916 if ( (NULL != cp->t) ||
917 (GNUNET_NO == create) )
919 cp->t = GCT_create_tunnel (cp);
920 consider_peer_activate (cp);
926 * Hello offer was passed to the transport service. Mark it
929 * @param cls the `struct CadetPeer` where the offer completed
932 hello_offer_done (void *cls)
934 struct CadetPeer *cp = cls;
936 cp->hello_offer = NULL;
941 * We got a HELLO for a @a peer, remember it, and possibly
942 * trigger adequate actions (like trying to connect).
944 * @param cp the peer we got a HELLO for
945 * @param hello the HELLO to remember
948 GCP_set_hello (struct CadetPeer *cp,
949 const struct GNUNET_HELLO_Message *hello)
951 struct GNUNET_HELLO_Message *mrg;
953 if (NULL != cp->hello_offer)
955 GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
956 cp->hello_offer = NULL;
958 if (NULL != cp->hello)
960 mrg = GNUNET_HELLO_merge (hello,
962 GNUNET_free (cp->hello);
967 cp->hello = GNUNET_memdup (hello,
968 GNUNET_HELLO_size (hello));
971 = GNUNET_TRANSPORT_offer_hello (cfg,
972 GNUNET_HELLO_get_header (cp->hello) ,
975 /* New HELLO means cp's destruction time may change... */
976 consider_peer_destroy (cp);
981 * The tunnel to the given peer no longer exists, remove it from our
982 * data structures, and possibly clean up the peer itself.
984 * @param cp the peer affected
985 * @param t the dead tunnel
988 GCP_drop_tunnel (struct CadetPeer *cp,
989 struct CadetTunnel *t)
991 GNUNET_assert (cp->t == t);
993 consider_peer_destroy (cp);
998 * Test if @a cp has a core-level connection
1000 * @param cp peer to test
1001 * @return #GNUNET_YES if @a cp has a core-level connection
1004 GCP_has_core_connection (struct CadetPeer *cp)
1006 return (NULL != cp->core_mq) ? GNUNET_YES : GNUNET_NO;
1011 * Start message queue change notifications.
1013 * @param cp peer to notify for
1014 * @param cb function to call if mq becomes available or unavailable
1015 * @param cb_cls closure for @a cb
1016 * @return handle to cancel request
1018 struct GCP_MessageQueueManager *
1019 GCP_request_mq (struct CadetPeer *cp,
1020 GCP_MessageQueueNotificationCallback cb,
1023 struct GCP_MessageQueueManager *mqm;
1025 mqm = GNUNET_new (struct GCP_MessageQueueManager);
1027 mqm->cb_cls = cb_cls;
1029 GNUNET_CONTAINER_DLL_insert (cp->mqm_head,
1032 if (NULL != cp->core_mq)
1040 * Stops message queue change notifications.
1042 * @param mqm handle matching request to cancel
1043 * @param last_env final message to transmit, or NULL
1046 GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
1047 struct GNUNET_MQ_Envelope *last_env)
1049 struct CadetPeer *cp = mqm->cp;
1051 if (NULL != mqm->env)
1052 GNUNET_MQ_discard (mqm->env);
1053 if (NULL != last_env)
1055 if (NULL != cp->core_mq)
1056 GNUNET_MQ_send (cp->core_mq,
1059 GNUNET_MQ_discard (last_env);
1061 GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
1069 * Send the message in @a env to @a cp, overriding queueing logic.
1070 * This function should only be used to send error messages outside
1071 * of flow and congestion control, similar to ICMP. Note that
1072 * the envelope may be silently discarded as well.
1074 * @param cp peer to send the message to
1075 * @param env envelope with the message to send
1078 GCP_send_ooo (struct CadetPeer *cp,
1079 struct GNUNET_MQ_Envelope *env)
1081 if (NULL == cp->core_mq)
1083 GNUNET_MQ_discard (env);
1086 GNUNET_MQ_send (cp->core_mq,
1093 /* end of gnunet-service-cadet-new_peer.c */