2 This file is part of GNUnet.
3 (C) 2010-2015 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 transport/gnunet-service-transport_neighbours.c
23 * @brief neighbour management
24 * @author Christian Grothoff
27 #include "gnunet_ats_service.h"
28 #include "gnunet-service-transport_ats.h"
29 #include "gnunet-service-transport_blacklist.h"
30 #include "gnunet-service-transport_clients.h"
31 #include "gnunet-service-transport_neighbours.h"
32 #include "gnunet-service-transport_manipulation.h"
33 #include "gnunet-service-transport_plugins.h"
34 #include "gnunet-service-transport_validation.h"
35 #include "gnunet-service-transport.h"
36 #include "gnunet_peerinfo_service.h"
37 #include "gnunet_constants.h"
38 #include "transport.h"
42 * Size of the neighbour hash map.
44 #define NEIGHBOUR_TABLE_SIZE 256
47 * Time we give plugin to transmit DISCONNECT message before the
48 * neighbour entry self-destructs.
50 #define DISCONNECT_SENT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500)
53 * How often must a peer violate bandwidth quotas before we start
54 * to simply drop its messages?
56 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
59 * How long are we willing to wait for a response from ATS before timing out?
61 #define ATS_RESPONSE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
64 * How long are we willing to wait for an ACK from the other peer before
65 * giving up on our connect operation?
67 #define SETUP_CONNECTION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
70 * How long are we willing to wait for a successful reconnect if
71 * an existing connection went down? Much shorter than the
72 * usual SETUP_CONNECTION_TIMEOUT as we do not inform the
73 * higher layers about the disconnect during this period.
75 #define FAST_RECONNECT_TIMEOUT GNUNET_TIME_UNIT_SECONDS
78 * Interval to send utilization data
80 #define UTIL_TRANSMISSION_INTERVAL GNUNET_TIME_UNIT_SECONDS
83 * State describing which kind a reply this neighbour should send
88 * We did not receive a SYN message for this neighbour
93 * The neighbour received a SYN message and has to send a SYN_ACK
99 * The neighbour sent a SYN_ACK message and has to send a ACK
106 GNUNET_NETWORK_STRUCT_BEGIN
109 * Message a peer sends to another to indicate that it intends to
110 * setup a connection/session for data exchange. A 'SESSION_SYN'
111 * should be answered with a 'SESSION_SYN_ACK' with the same body
112 * to confirm. A 'SESSION_SYN_ACK' should then be followed with
113 * a 'ACK'. Once the 'ACK' is received, both peers
114 * should be connected.
116 struct TransportSynMessage
119 * Header of type #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN
120 * or #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN_ACK
122 struct GNUNET_MessageHeader header;
127 uint32_t reserved GNUNET_PACKED;
130 * Absolute time at the sender. Only the most recent connect
131 * message implies which session is preferred by the sender.
133 struct GNUNET_TIME_AbsoluteNBO timestamp;
139 * Message a peer sends to another when connected to indicate that a
140 * session is in use and the peer is still alive or to respond to a keep alive.
141 * A peer sends a message with type #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE
142 * to request a message with #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE_RESPONSE.
143 * When the keep alive response with type is received, transport service
144 * will call the respective plugin to update the session timeout
146 struct SessionKeepAliveMessage
149 * Header of type #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE or
150 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE_RESPONSE.
152 struct GNUNET_MessageHeader header;
155 * A nonce to identify the session the keep alive is used for
157 uint32_t nonce GNUNET_PACKED;
161 * Message we send to the other peer to notify him that we intentionally
162 * are disconnecting (to reduce timeouts). This is just a friendly
163 * notification, peers must not rely on always receiving disconnect
166 struct SessionDisconnectMessage
169 * Header of type #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT
171 struct GNUNET_MessageHeader header;
176 uint32_t reserved GNUNET_PACKED;
179 * Purpose of the signature. Extends over the timestamp.
180 * Purpose should be #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DISCONNECT.
182 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
185 * Absolute time at the sender. Only the most recent connect
186 * message implies which session is preferred by the sender.
188 struct GNUNET_TIME_AbsoluteNBO timestamp;
191 * Public key of the sender.
193 struct GNUNET_CRYPTO_EddsaPublicKey public_key;
196 * Signature of the peer that sends us the disconnect. Only
197 * valid if the timestamp is AFTER the timestamp from the
198 * corresponding 'SYN' message.
200 struct GNUNET_CRYPTO_EddsaSignature signature;
204 GNUNET_NETWORK_STRUCT_END
208 * For each neighbour we keep a list of messages
209 * that we still want to transmit to the neighbour.
215 * This is a doubly linked list.
217 struct MessageQueue *next;
220 * This is a doubly linked list.
222 struct MessageQueue *prev;
225 * Function to call once we're done.
227 GST_NeighbourSendContinuation cont;
230 * Closure for @e cont
235 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
236 * stuck together in memory. Allocated at the end of this struct.
238 const char *message_buf;
241 * Size of the message buf
243 size_t message_buf_size;
246 * At what time should we fail?
248 struct GNUNET_TIME_Absolute timeout;
254 * A possible address we could use to communicate with a neighbour.
256 struct NeighbourAddress
260 * Active session for this address.
262 struct Session *session;
265 * Network-level address information.
267 struct GNUNET_HELLO_Address *address;
270 * Timestamp of the 'SESSION_CONNECT' message we sent to the other
271 * peer for this address. Use to check that the ACK is in response
272 * to our most recent 'SYN'.
274 struct GNUNET_TIME_Absolute connect_timestamp;
277 * Inbound bandwidth from ATS for this address.
279 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
282 * Outbound bandwidth from ATS for this address.
284 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
287 * Did we tell ATS that this is our 'active' address?
292 * The current nonce sent in the last keep alive messages
294 uint32_t keep_alive_nonce;
299 * Entry in neighbours.
301 struct NeighbourMapEntry
305 * Head of list of messages we would like to send to this peer;
306 * must contain at most one message per client.
308 struct MessageQueue *messages_head;
311 * Tail of list of messages we would like to send to this peer; must
312 * contain at most one message per client.
314 struct MessageQueue *messages_tail;
317 * Are we currently trying to send a message? If so, which one?
319 struct MessageQueue *is_active;
322 * Primary address we currently use to communicate with the neighbour.
324 struct NeighbourAddress primary_address;
327 * Alternative address currently under consideration for communicating
328 * with the neighbour.
330 struct NeighbourAddress alternative_address;
333 * Identity of this neighbour.
335 struct GNUNET_PeerIdentity id;
338 * Main task that drives this peer (timeouts, keepalives, etc.).
339 * Always runs the 'master_task'.
341 struct GNUNET_SCHEDULER_Task *task;
344 * Task to disconnect neighbour after we received a DISCONNECT message
346 struct GNUNET_SCHEDULER_Task *delayed_disconnect_task;
349 * At what time should we sent the next keep-alive message?
351 struct GNUNET_TIME_Absolute keep_alive_time;
354 * At what time did we sent the last keep-alive message? Used
355 * to calculate round-trip time ("latency").
357 struct GNUNET_TIME_Absolute last_keep_alive_time;
360 * Timestamp we should include in our next SYN_ACK message.
361 * (only valid if 'send_connect_ack' is #GNUNET_YES). Used to build
362 * our SYN_ACK message.
364 struct GNUNET_TIME_Absolute connect_ack_timestamp;
367 * ATS address suggest handle
369 struct GNUNET_ATS_ConnectivitySuggestHandle *suggest_handle;
372 * Time where we should cut the connection (timeout) if we don't
373 * make progress in the state machine (or get a KEEPALIVE_RESPONSE
374 * if we are in #S_CONNECTED).
376 struct GNUNET_TIME_Absolute timeout;
379 * Tracker for inbound bandwidth.
381 struct GNUNET_BANDWIDTH_Tracker in_tracker;
384 * How often has the other peer (recently) violated the inbound
385 * traffic limit? Incremented by 10 per violation, decremented by 1
386 * per non-violation (for each time interval).
388 unsigned int quota_violation_count;
391 * The current state of the peer.
393 enum GNUNET_TRANSPORT_PeerState state;
396 * Did we sent an KEEP_ALIVE message and are we expecting a response?
398 int expect_latency_response;
401 * When a peer wants to connect we have to reply to the 1st SYN message
402 * with a SYN_ACK message. But sometime we cannot send this message
403 * immediately since we do not have an address and then we have to remember
404 * to send this message as soon as we have an address.
406 * Flag to set if we still need to send a SYN_ACK message to the other peer
407 * (once we have an address to use and the peer has been allowed by our
408 * blacklist). Initially set to #ACK_UNDEFINED. Set to #ACK_SEND_SYN_ACK
409 * if we need to send a SYN_ACK. Set to #ACK_SEND_ACK if we did
410 * send a SYN_ACK and should go to #S_CONNECTED upon receiving a
411 * 'ACK' (regardless of what our own state machine might say).
413 enum GST_ACK_State ack_state;
416 * Tracking utilization of outbound bandwidth
418 uint32_t util_payload_bytes_sent;
421 * Tracking utilization of inbound bandwidth
423 uint32_t util_payload_bytes_recv;
426 * Tracking utilization of outbound bandwidth
428 uint32_t util_total_bytes_sent;
431 * Tracking utilization of inbound bandwidth
433 uint32_t util_total_bytes_recv;
436 * Date of last utilization transmission
438 struct GNUNET_TIME_Absolute last_util_transmission;
443 * Context for blacklist checks and the #try_connect_bl_check_cont()
444 * function. Stores information about ongoing blacklist checks.
446 struct BlackListCheckContext
450 * We keep blacklist checks in a DLL.
452 struct BlackListCheckContext *next;
455 * We keep blacklist checks in a DLL.
457 struct BlackListCheckContext *prev;
460 * Address that is being checked.
462 struct NeighbourAddress na;
465 * Handle to the ongoing blacklist check.
467 struct GST_BlacklistCheck *bc;
472 * Hash map from peer identities to the respective `struct NeighbourMapEntry`.
474 static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
477 * We keep blacklist checks in a DLL so that we can find
478 * the 'sessions' in their 'struct NeighbourAddress' if
479 * a session goes down.
481 static struct BlackListCheckContext *bc_head;
484 * We keep blacklist checks in a DLL.
486 static struct BlackListCheckContext *bc_tail;
489 * List of pending blacklist checks: head
491 static struct BlacklistCheckSwitchContext *pending_bc_head;
494 * List of pending blacklist checks: tail
496 static struct BlacklistCheckSwitchContext *pending_bc_tail;
499 * counter for connected neighbours
501 static unsigned int neighbours_connected;
504 * Number of bytes we have currently queued for transmission.
506 static unsigned long long bytes_in_send_queue;
509 * Task transmitting utilization data
511 static struct GNUNET_SCHEDULER_Task *util_transmission_tk;
515 * Convert the given ACK state to a string.
518 * @return corresponding human-readable string
521 print_ack_state (enum GST_ACK_State s)
526 case ACK_SEND_SYN_ACK:
527 return "SEND_SYN_ACK";
538 * Notify our clients that another peer connected to us.
540 * @param peer the peer that connected
541 * @param bandwidth_in inbound bandwidth in NBO
542 * @param bandwidth_out outbound bandwidth in NBO
545 neighbours_connect_notification (const struct GNUNET_PeerIdentity *peer,
546 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
547 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
549 size_t len = sizeof(struct ConnectInfoMessage);
550 char buf[len] GNUNET_ALIGN;
551 struct ConnectInfoMessage *connect_msg = (struct ConnectInfoMessage *) buf;
553 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
554 "We are now connected to peer `%s'\n",
556 connect_msg->header.size = htons (sizeof(buf));
557 connect_msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
558 connect_msg->id = *peer;
559 connect_msg->quota_in = bandwidth_in;
560 connect_msg->quota_out = bandwidth_out;
561 GST_clients_broadcast (&connect_msg->header, GNUNET_NO);
566 * Notify our clients (and manipulation) that a peer disconnected from
569 * @param peer the peer that disconnected
572 neighbours_disconnect_notification (const struct GNUNET_PeerIdentity *peer)
574 struct DisconnectInfoMessage disconnect_msg;
576 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
577 "Peer `%s' disconnected\n",
579 GST_manipulation_peer_disconnect (peer);
580 disconnect_msg.header.size = htons (sizeof(struct DisconnectInfoMessage));
581 disconnect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
582 disconnect_msg.reserved = htonl (0);
583 disconnect_msg.peer = *peer;
584 GST_clients_broadcast (&disconnect_msg.header,
590 * Notify transport clients that a neighbour peer changed its active
593 * @param peer identity of the peer
594 * @param address address possibly NULL if peer is not connected
595 * @param state current state this peer is in
596 * @param state_timeout timeout for the current state of the peer
597 * @param bandwidth_in bandwidth assigned inbound, 0 on disconnect
598 * @param bandwidth_out bandwidth assigned outbound, 0 on disconnect
601 neighbours_changed_notification (const struct GNUNET_PeerIdentity *peer,
602 const struct GNUNET_HELLO_Address *address,
603 enum GNUNET_TRANSPORT_PeerState state,
604 struct GNUNET_TIME_Absolute state_timeout,
605 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
606 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
608 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
609 "Notifying about change for peer `%s' with address `%s' in state `%s' timing out at %s\n",
611 GST_plugins_a2s (address),
612 GNUNET_TRANSPORT_ps2s (state),
613 GNUNET_STRINGS_absolute_time_to_string (state_timeout));
614 /* FIXME: include bandwidth in notification! */
615 GST_clients_broadcast_peer_notification (peer,
623 * Lookup a neighbour entry in the neighbours hash map.
625 * @param pid identity of the peer to look up
626 * @return the entry, NULL if there is no existing record
628 static struct NeighbourMapEntry *
629 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
631 if (NULL == neighbours)
633 return GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
638 * Test if we're connected to the given peer.
640 * @param n neighbour entry of peer to test
641 * @return #GNUNET_YES if we are connected, #GNUNET_NO if not
644 test_connected (struct NeighbourMapEntry *n)
648 return GNUNET_TRANSPORT_is_connected (n->state);
653 * Send information about a new outbound quota to our clients.
655 * @param target affected peer
656 * @param quota new quota
659 send_outbound_quota (const struct GNUNET_PeerIdentity *target,
660 struct GNUNET_BANDWIDTH_Value32NBO quota)
662 struct QuotaSetMessage q_msg;
664 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
665 "Sending outbound quota of %u Bps for peer `%s' to all clients\n",
666 ntohl (quota.value__),
667 GNUNET_i2s (target));
668 q_msg.header.size = htons (sizeof (struct QuotaSetMessage));
669 q_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA);
671 q_msg.peer = (*target);
672 GST_clients_broadcast (&q_msg.header, GNUNET_NO);
677 * We don't need a given neighbour address any more.
678 * Release its resources and give appropriate notifications
679 * to ATS and other subsystems.
681 * @param na address we are done with; @a na itself must NOT be 'free'd, only the contents!
684 free_address (struct NeighbourAddress *na)
686 if (GNUNET_YES == na->ats_active)
687 GST_validation_set_address_use (na->address,
689 if (NULL != na->address)
691 GST_ats_block_address (na->address,
693 GNUNET_HELLO_address_free (na->address);
696 na->bandwidth_in = GNUNET_BANDWIDTH_value_init (0);
697 na->bandwidth_out = GNUNET_BANDWIDTH_value_init (0);
698 na->ats_active = GNUNET_NO;
699 na->keep_alive_nonce = 0;
705 * Master task run for every neighbour. Performs all of the time-related
706 * activities (keep alive, send next message, disconnect if idle, finish
707 * clean up after disconnect).
709 * @param cls the `struct NeighbourMapEntry` for which we are running
710 * @param tc scheduler context (unused)
713 master_task (void *cls,
714 const struct GNUNET_SCHEDULER_TaskContext *tc);
718 * Set net state and state timeout for this neighbour and notify monitoring
720 * @param n the respective neighbour
721 * @param s the new state
722 * @param timeout the new timeout
725 set_state_and_timeout (struct NeighbourMapEntry *n,
726 enum GNUNET_TRANSPORT_PeerState s,
727 struct GNUNET_TIME_Absolute timeout)
729 if (GNUNET_TRANSPORT_is_connected (s) &&
730 ! GNUNET_TRANSPORT_is_connected (n->state) )
732 neighbours_connect_notification (&n->id,
733 n->primary_address.bandwidth_in,
734 n->primary_address.bandwidth_out);
735 GNUNET_STATISTICS_set (GST_stats,
736 gettext_noop ("# peers connected"),
737 ++neighbours_connected,
740 if (! GNUNET_TRANSPORT_is_connected (s) &&
741 GNUNET_TRANSPORT_is_connected (n->state) )
743 GNUNET_STATISTICS_set (GST_stats,
744 gettext_noop ("# peers connected"),
745 --neighbours_connected,
747 neighbours_disconnect_notification (&n->id);
750 if ( (timeout.abs_value_us < n->timeout.abs_value_us) &&
753 /* new timeout is earlier, reschedule master task */
754 GNUNET_SCHEDULER_cancel (n->task);
755 n->task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (timeout),
759 n->timeout = timeout;
760 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
761 "Neighbour `%s' changed state to %s with timeout %s\n",
763 GNUNET_TRANSPORT_ps2s(s),
764 GNUNET_STRINGS_absolute_time_to_string (timeout));
765 neighbours_changed_notification (&n->id,
766 n->primary_address.address,
769 n->primary_address.bandwidth_in,
770 n->primary_address.bandwidth_out);
775 * Initialize the alternative address of a neighbour
777 * @param n the neighbour
778 * @param address address of the other peer, NULL if other peer
780 * @param session session to use (or NULL, in which case an
781 * address must be setup)
782 * @param bandwidth_in inbound quota to be used when connection is up
783 * @param bandwidth_out outbound quota to be used when connection is up
786 set_alternative_address (struct NeighbourMapEntry *n,
787 const struct GNUNET_HELLO_Address *address,
788 struct Session *session,
789 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
790 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
792 struct GNUNET_TRANSPORT_PluginFunctions *papi;
794 if (NULL == (papi = GST_plugins_find (address->transport_name)))
799 if (session == n->alternative_address.session)
801 n->alternative_address.bandwidth_in = bandwidth_in;
802 n->alternative_address.bandwidth_out = bandwidth_out;
805 if (NULL != n->alternative_address.address)
807 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
808 "Replacing existing alternative address with another one\n");
809 free_address (&n->alternative_address);
812 session = papi->get_session (papi->cls,
816 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
817 "Failed to obtain new session for peer `%s' and address '%s'\n",
818 GNUNET_i2s (&address->peer),
819 GST_plugins_a2s (address));
820 GNUNET_STATISTICS_update (GST_stats,
821 gettext_noop ("# session creation failed"),
826 GST_ats_new_session (address,
828 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
829 "Neighbour `%s' configured alternative address %s\n",
831 GST_plugins_a2s(address));
833 n->alternative_address.address = GNUNET_HELLO_address_copy (address);
834 n->alternative_address.bandwidth_in = bandwidth_in;
835 n->alternative_address.bandwidth_out = bandwidth_out;
836 n->alternative_address.session = session;
837 n->alternative_address.ats_active = GNUNET_NO;
838 n->alternative_address.keep_alive_nonce = 0;
843 * Initialize the primary address of a neighbour
845 * @param n the neighbour
846 * @param address address of the other peer, NULL if other peer
848 * @param session session to use (or NULL, in which case an
849 * address must be setup)
850 * @param bandwidth_in inbound quota to be used when connection is up
851 * @param bandwidth_out outbound quota to be used when connection is up
852 * @param is_active #GNUNET_YES to mark this as the active address with ATS
855 set_primary_address (struct NeighbourMapEntry *n,
856 const struct GNUNET_HELLO_Address *address,
857 struct Session *session,
858 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
859 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
862 if (session == n->primary_address.session)
864 if (is_active != n->primary_address.ats_active)
866 n->primary_address.ats_active = is_active;
867 GST_validation_set_address_use (n->primary_address.address,
870 if (GNUNET_YES == is_active)
872 if (n->primary_address.bandwidth_in.value__ != bandwidth_in.value__)
874 n->primary_address.bandwidth_in = bandwidth_in;
875 GST_neighbours_set_incoming_quota (&address->peer, bandwidth_in);
877 if (n->primary_address.bandwidth_out.value__ != bandwidth_out.value__)
879 n->primary_address.bandwidth_out = bandwidth_out;
880 send_outbound_quota (&address->peer,
886 if ( (NULL != n->primary_address.address) &&
887 (0 == GNUNET_HELLO_address_cmp (address,
888 n->primary_address.address)) )
896 GST_ats_block_address (address,
900 if (NULL != n->primary_address.address)
902 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
903 "Replacing existing primary address with another one\n");
904 free_address (&n->primary_address);
906 n->primary_address.address = GNUNET_HELLO_address_copy (address);
907 n->primary_address.bandwidth_in = bandwidth_in;
908 n->primary_address.bandwidth_out = bandwidth_out;
909 n->primary_address.session = session;
910 n->primary_address.ats_active = is_active;
911 n->primary_address.keep_alive_nonce = 0;
912 if (GNUNET_YES == is_active)
914 /* subsystems about address use */
915 GST_validation_set_address_use (n->primary_address.address,
917 GST_neighbours_set_incoming_quota (&address->peer, bandwidth_in);
918 send_outbound_quota (&address->peer,
922 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
923 "Neighbour `%s' switched to address `%s'\n",
925 GST_plugins_a2s(address));
927 neighbours_changed_notification (&n->id,
928 n->primary_address.address,
931 n->primary_address.bandwidth_in,
932 n->primary_address.bandwidth_out);
937 * Clear the primary address of a neighbour since this address is not
938 * valid anymore and notify monitoring about it
940 * @param n the neighbour
943 unset_primary_address (struct NeighbourMapEntry *n)
945 /* Notify monitoring about change */
946 if (NULL == n->primary_address.address)
948 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
949 "Disabling primary address\n");
950 neighbours_changed_notification (&n->id,
951 n->primary_address.address,
954 GNUNET_BANDWIDTH_value_init (0),
955 GNUNET_BANDWIDTH_value_init (0));
956 free_address (&n->primary_address);
961 * Free a neighbour map entry.
963 * @param n entry to free
966 free_neighbour (struct NeighbourMapEntry *n)
968 struct MessageQueue *mq;
970 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
971 "Freeing neighbour state of peer `%s'\n",
972 GNUNET_i2s (&n->id));
973 n->is_active = NULL; /* always free'd by its own continuation! */
975 /* fail messages currently in the queue */
976 while (NULL != (mq = n->messages_head))
978 GNUNET_CONTAINER_DLL_remove (n->messages_head,
981 if (NULL != mq->cont)
982 mq->cont (mq->cont_cls,
984 mq->message_buf_size,
988 /* Mark peer as disconnected */
989 set_state_and_timeout (n,
990 GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED,
991 GNUNET_TIME_UNIT_FOREVER_ABS);
992 /* free addresses and mark as unused */
993 unset_primary_address (n);
995 if (NULL != n->alternative_address.address)
997 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
998 "Cleaning up alternative address\n");
999 free_address (&n->alternative_address);
1001 GNUNET_assert (GNUNET_YES ==
1002 GNUNET_CONTAINER_multipeermap_remove (neighbours,
1005 /* Cancel address requests for this peer */
1006 if (NULL != n->suggest_handle)
1008 GNUNET_ATS_connectivity_suggest_cancel (n->suggest_handle);
1009 n->suggest_handle = NULL;
1012 /* Cancel the disconnect task */
1013 if (NULL != n->delayed_disconnect_task)
1015 GNUNET_SCHEDULER_cancel (n->delayed_disconnect_task);
1016 n->delayed_disconnect_task = NULL;
1019 /* Cancel the master task */
1020 if (NULL != n->task)
1022 GNUNET_SCHEDULER_cancel (n->task);
1025 /* free rest of memory */
1031 * Transmit a message using the current session of the given
1034 * @param n entry for the recipient
1035 * @param msgbuf buffer to transmit
1036 * @param msgbuf_size number of bytes in @a msgbuf buffer
1037 * @param priority transmission priority
1038 * @param timeout transmission timeout
1039 * @param use_keepalive_timeout #GNUNET_YES to use plugin-specific keep-alive
1040 * timeout (@a timeout is ignored in that case), #GNUNET_NO otherwise
1041 * @param cont continuation to call when finished (can be NULL)
1042 * @param cont_cls closure for @a cont
1043 * @return timeout (copy of @a timeout or a calculated one if
1044 * @a use_keepalive_timeout is #GNUNET_YES.
1046 static struct GNUNET_TIME_Relative
1047 send_with_session (struct NeighbourMapEntry *n,
1051 struct GNUNET_TIME_Relative timeout,
1052 unsigned int use_keepalive_timeout,
1053 GNUNET_TRANSPORT_TransmitContinuation cont,
1056 struct GNUNET_TRANSPORT_PluginFunctions *papi;
1057 struct GNUNET_TIME_Relative result = GNUNET_TIME_UNIT_FOREVER_REL;
1059 GNUNET_assert (n->primary_address.session != NULL);
1060 if ( ((NULL == (papi = GST_plugins_find (n->primary_address.address->transport_name)) ||
1061 (-1 == papi->send (papi->cls,
1062 n->primary_address.session,
1066 (result = (GNUNET_NO == use_keepalive_timeout) ? timeout :
1067 GNUNET_TIME_relative_divide (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1068 papi->query_keepalive_factor (papi->cls))),
1077 GST_neighbours_notify_data_sent (n->primary_address.address,
1078 n->primary_address.session,
1080 GNUNET_break (NULL != papi);
1086 * Function called when the 'DISCONNECT' message has been sent by the
1087 * plugin. Frees the neighbour --- if the entry still exists.
1090 * @param target identity of the neighbour that was disconnected
1091 * @param result #GNUNET_OK if the disconnect got out successfully
1092 * @param payload bytes payload
1093 * @param physical bytes on wire
1096 send_disconnect_cont (void *cls,
1097 const struct GNUNET_PeerIdentity *target,
1102 struct NeighbourMapEntry *n;
1104 n = lookup_neighbour (target);
1106 return; /* already gone */
1107 if (GNUNET_TRANSPORT_PS_DISCONNECT != n->state)
1108 return; /* have created a fresh entry since */
1109 if (NULL != n->task)
1110 GNUNET_SCHEDULER_cancel (n->task);
1111 n->task = GNUNET_SCHEDULER_add_now (&master_task, n);
1116 * Transmit a DISCONNECT message to the other peer.
1118 * @param n neighbour to send DISCONNECT message.
1121 send_disconnect (struct NeighbourMapEntry *n)
1123 struct SessionDisconnectMessage disconnect_msg;
1125 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1126 "Sending DISCONNECT message to peer `%4s'\n",
1127 GNUNET_i2s (&n->id));
1128 disconnect_msg.header.size = htons (sizeof (struct SessionDisconnectMessage));
1129 disconnect_msg.header.type =
1130 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT);
1131 disconnect_msg.reserved = htonl (0);
1132 disconnect_msg.purpose.size =
1133 htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
1134 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey) +
1135 sizeof (struct GNUNET_TIME_AbsoluteNBO));
1136 disconnect_msg.purpose.purpose =
1137 htonl (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT);
1138 disconnect_msg.timestamp =
1139 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
1140 disconnect_msg.public_key = GST_my_identity.public_key;
1141 GNUNET_assert (GNUNET_OK ==
1142 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
1143 &disconnect_msg.purpose,
1144 &disconnect_msg.signature));
1146 (void) send_with_session (n,
1148 sizeof (disconnect_msg),
1150 GNUNET_TIME_UNIT_FOREVER_REL,
1152 &send_disconnect_cont,
1154 GNUNET_STATISTICS_update (GST_stats,
1155 gettext_noop ("# DISCONNECT messages sent"),
1162 * Disconnect from the given neighbour, clean up the record.
1164 * @param n neighbour to disconnect from
1167 disconnect_neighbour (struct NeighbourMapEntry *n)
1169 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1170 "Disconnecting from peer %s in state %s\n",
1171 GNUNET_i2s (&n->id),
1172 GNUNET_TRANSPORT_ps2s (n->state));
1173 /* depending on state, notify neighbour and/or upper layers of this peer
1177 case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
1178 case GNUNET_TRANSPORT_PS_INIT_ATS:
1179 /* other peer is completely unaware of us, no need to send DISCONNECT */
1182 case GNUNET_TRANSPORT_PS_SYN_SENT:
1183 send_disconnect (n);
1184 set_state_and_timeout (n,
1185 GNUNET_TRANSPORT_PS_DISCONNECT,
1186 GNUNET_TIME_UNIT_FOREVER_ABS);
1188 case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
1189 /* we never ACK'ed the other peer's request, no need to send DISCONNECT */
1192 case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
1193 /* we DID ACK the other peer's request, must send DISCONNECT */
1194 send_disconnect (n);
1195 set_state_and_timeout (n,
1196 GNUNET_TRANSPORT_PS_DISCONNECT,
1197 GNUNET_TIME_UNIT_FOREVER_ABS);
1199 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
1200 case GNUNET_TRANSPORT_PS_CONNECTED:
1201 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
1202 /* we are currently connected, need to send disconnect and do
1203 internal notifications and update statistics */
1204 send_disconnect (n);
1205 set_state_and_timeout (n,
1206 GNUNET_TRANSPORT_PS_DISCONNECT,
1207 GNUNET_TIME_UNIT_FOREVER_ABS);
1209 case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
1210 /* Disconnecting while waiting for an ATS address to reconnect,
1211 * cannot send DISCONNECT */
1214 case GNUNET_TRANSPORT_PS_DISCONNECT:
1215 /* already disconnected, ignore */
1217 case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
1218 /* already cleaned up, how did we get here!? */
1222 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1223 "Unhandled state `%s'\n",
1224 GNUNET_TRANSPORT_ps2s (n->state));
1228 /* schedule timeout to clean up */
1229 if (NULL != n->task)
1230 GNUNET_SCHEDULER_cancel (n->task);
1231 n->task = GNUNET_SCHEDULER_add_delayed (DISCONNECT_SENT_TIMEOUT,
1238 * We're done with our transmission attempt, continue processing.
1240 * @param cls the `struct MessageQueue` of the message
1241 * @param receiver intended receiver
1242 * @param success whether it worked or not
1243 * @param size_payload bytes payload sent
1244 * @param physical bytes sent on wire
1247 transmit_send_continuation (void *cls,
1248 const struct GNUNET_PeerIdentity *receiver,
1249 int success, size_t size_payload, size_t physical)
1251 struct MessageQueue *mq = cls;
1252 struct NeighbourMapEntry *n;
1254 if (NULL == (n = lookup_neighbour (receiver)))
1257 return; /* disconnect or other error while transmitting, can happen */
1259 if (n->is_active == mq)
1261 /* this is still "our" neighbour, remove us from its queue
1262 and allow it to send the next message now */
1263 n->is_active = NULL;
1264 if (NULL != n->task)
1265 GNUNET_SCHEDULER_cancel (n->task);
1266 n->task = GNUNET_SCHEDULER_add_now (&master_task, n);
1268 if (bytes_in_send_queue < mq->message_buf_size)
1270 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1271 "Bytes_in_send_queue `%u', Message_size %u, result: %s, payload %u, on wire %u\n",
1272 bytes_in_send_queue,
1273 mq->message_buf_size,
1274 (GNUNET_OK == success) ? "OK" : "FAIL",
1281 GNUNET_break (size_payload == mq->message_buf_size);
1282 bytes_in_send_queue -= mq->message_buf_size;
1283 GNUNET_STATISTICS_set (GST_stats,
1285 ("# bytes in message queue for other peers"),
1286 bytes_in_send_queue, GNUNET_NO);
1287 if (GNUNET_OK == success)
1288 GNUNET_STATISTICS_update (GST_stats,
1290 ("# messages transmitted to other peers"),
1293 GNUNET_STATISTICS_update (GST_stats,
1295 ("# transmission failures for messages to other peers"),
1297 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1298 "Sending message to `%s' of type %u with %u bytes was a %s\n",
1299 GNUNET_i2s (receiver),
1300 ntohs (((struct GNUNET_MessageHeader *) mq->message_buf)->type),
1301 mq->message_buf_size,
1302 (success == GNUNET_OK) ? "success" : "FAILURE");
1303 if (NULL != mq->cont)
1304 mq->cont (mq->cont_cls, success, size_payload, physical);
1310 * Check the message list for the given neighbour and if we can
1311 * send a message, do so. This function should only be called
1312 * if the connection is at least generally ready for transmission.
1313 * While we will only send one message at a time, no bandwidth
1314 * quota management is performed here. If a message was given to
1315 * the plugin, the continuation will automatically re-schedule
1316 * the 'master' task once the next message might be transmitted.
1318 * @param n target peer for which to transmit
1321 try_transmission_to_peer (struct NeighbourMapEntry *n)
1323 struct MessageQueue *mq;
1324 struct GNUNET_TIME_Relative timeout;
1326 if (NULL == n->primary_address.address)
1328 /* no address, why are we here? */
1332 if ((0 == n->primary_address.address->address_length) &&
1333 (NULL == n->primary_address.session))
1335 /* no address, why are we here? */
1339 if (NULL != n->is_active)
1341 /* transmission already pending */
1345 /* timeout messages from the queue that are past their due date */
1346 while (NULL != (mq = n->messages_head))
1348 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1349 if (timeout.rel_value_us > 0)
1351 GNUNET_STATISTICS_update (GST_stats,
1353 ("# messages timed out while in transport queue"),
1355 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1359 transmit_send_continuation (mq,
1362 mq->message_buf_size,
1366 return; /* no more messages */
1367 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1372 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1373 "Giving message with %u bytes to plugin session %p\n",
1374 mq->message_buf_size,
1375 n->primary_address.session);
1376 (void) send_with_session (n,
1378 mq->message_buf_size,
1382 &transmit_send_continuation,
1388 * Send keepalive message to the neighbour. Must only be called
1389 * if we are on 'connected' state or while trying to switch addresses.
1390 * Will internally determine if a keepalive is truly needed (so can
1391 * always be called).
1393 * @param n neighbour that went idle and needs a keepalive
1396 send_keepalive (struct NeighbourMapEntry *n)
1398 struct SessionKeepAliveMessage m;
1399 struct GNUNET_TIME_Relative timeout;
1402 GNUNET_assert ((GNUNET_TRANSPORT_PS_CONNECTED == n->state) ||
1403 (GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT == n->state));
1404 if (GNUNET_TIME_absolute_get_remaining (n->keep_alive_time).rel_value_us > 0)
1405 return; /* no keepalive needed at this time */
1407 nonce = 0; /* 0 indicates 'not set' */
1409 nonce = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
1411 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1412 "Sending keep alive to peer `%s' with nonce %u\n",
1413 GNUNET_i2s (&n->id),
1415 m.header.size = htons (sizeof (struct SessionKeepAliveMessage));
1416 m.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE);
1417 m.nonce = htonl (nonce);
1419 timeout = send_with_session (n,
1422 UINT32_MAX /* priority */,
1423 GNUNET_TIME_UNIT_FOREVER_REL,
1426 GNUNET_STATISTICS_update (GST_stats,
1427 gettext_noop ("# keepalives sent"),
1430 n->primary_address.keep_alive_nonce = nonce;
1431 n->expect_latency_response = GNUNET_YES;
1432 n->last_keep_alive_time = GNUNET_TIME_absolute_get ();
1433 n->keep_alive_time = GNUNET_TIME_relative_to_absolute (timeout);
1438 * Keep the connection to the given neighbour alive longer,
1439 * we received a KEEPALIVE (or equivalent); send a response.
1441 * @param neighbour neighbour to keep alive (by sending keep alive response)
1442 * @param m the keep alive message containing the nonce to respond to
1445 GST_neighbours_keepalive (const struct GNUNET_PeerIdentity *neighbour,
1446 const struct GNUNET_MessageHeader *m)
1448 struct NeighbourMapEntry *n;
1449 const struct SessionKeepAliveMessage *msg_in;
1450 struct SessionKeepAliveMessage msg;
1452 if (sizeof (struct SessionKeepAliveMessage) != ntohs (m->size))
1455 msg_in = (struct SessionKeepAliveMessage *) m;
1456 if (NULL == (n = lookup_neighbour (neighbour)))
1458 GNUNET_STATISTICS_update (GST_stats,
1460 ("# KEEPALIVE messages discarded (peer unknown)"),
1464 if (NULL == n->primary_address.session)
1466 GNUNET_STATISTICS_update (GST_stats,
1468 ("# KEEPALIVE messages discarded (no session)"),
1473 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1474 "Received keep alive request from peer `%s' with nonce %u\n",
1475 GNUNET_i2s (&n->id), ntohl (msg_in->nonce));
1477 /* send reply to allow neighbour to measure latency */
1478 msg.header.size = htons (sizeof (struct SessionKeepAliveMessage));
1479 msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE_RESPONSE);
1480 msg.nonce = msg_in->nonce;
1481 (void) send_with_session (n,
1483 sizeof (struct SessionKeepAliveMessage),
1484 UINT32_MAX /* priority */,
1485 GNUNET_TIME_UNIT_FOREVER_REL,
1492 * We received a KEEP_ALIVE_RESPONSE message and use this to calculate
1493 * latency to this peer. Pass the updated information (existing ats
1494 * plus calculated latency) to ATS.
1496 * @param neighbour neighbour to keep alive
1497 * @param m the message containing the keep alive response
1500 GST_neighbours_keepalive_response (const struct GNUNET_PeerIdentity *neighbour,
1501 const struct GNUNET_MessageHeader *m)
1503 struct NeighbourMapEntry *n;
1504 const struct SessionKeepAliveMessage *msg;
1505 struct GNUNET_TRANSPORT_PluginFunctions *papi;
1506 struct GNUNET_ATS_Information ats;
1507 struct GNUNET_TIME_Relative latency;
1509 if (sizeof (struct SessionKeepAliveMessage) != ntohs (m->size))
1512 msg = (const struct SessionKeepAliveMessage *) m;
1513 if (NULL == (n = lookup_neighbour (neighbour)))
1515 GNUNET_STATISTICS_update (GST_stats,
1517 ("# KEEPALIVE_RESPONSE messages discarded (not connected)"),
1521 if ( (GNUNET_TRANSPORT_PS_CONNECTED != n->state) ||
1522 (GNUNET_YES != n->expect_latency_response) )
1524 GNUNET_STATISTICS_update (GST_stats,
1526 ("# KEEPALIVE_RESPONSE messages discarded (not expected)"),
1530 if (NULL == n->primary_address.address)
1532 GNUNET_STATISTICS_update (GST_stats,
1534 ("# KEEPALIVE_RESPONSE messages discarded (address changed)"),
1538 if (n->primary_address.keep_alive_nonce != ntohl (msg->nonce))
1540 GNUNET_STATISTICS_update (GST_stats,
1542 ("# KEEPALIVE_RESPONSE messages discarded (wrong nonce)"),
1548 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1549 "Received keep alive response from peer `%s' for session %p\n",
1550 GNUNET_i2s (&n->id), n->primary_address.session);
1554 /* Update session timeout here */
1555 if (NULL != (papi = GST_plugins_find (n->primary_address.address->transport_name)))
1557 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1558 "Updating session for peer `%s' for session %p\n",
1559 GNUNET_i2s (&n->id), n->primary_address.session);
1560 papi->update_session_timeout (papi->cls, &n->id, n->primary_address.session);
1567 n->primary_address.keep_alive_nonce = 0;
1568 n->expect_latency_response = GNUNET_NO;
1569 set_state_and_timeout (n,
1571 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT));
1573 latency = GNUNET_TIME_absolute_get_duration (n->last_keep_alive_time);
1574 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1575 "Latency for peer `%s' is %s\n",
1576 GNUNET_i2s (&n->id),
1577 GNUNET_STRINGS_relative_time_to_string (latency,
1579 /* append latency */
1580 ats.type = htonl (GNUNET_ATS_QUALITY_NET_DELAY);
1581 ats.value = htonl ( (latency.rel_value_us > UINT32_MAX)
1583 : (uint32_t) latency.rel_value_us );
1584 GST_ats_update_metrics (n->primary_address.address,
1585 n->primary_address.session,
1591 * We have received a message from the given sender. How long should
1592 * we delay before receiving more? (Also used to keep the peer marked
1595 * @param sender sender of the message
1596 * @param size size of the message
1597 * @param do_forward set to #GNUNET_YES if the message should be forwarded to clients
1598 * #GNUNET_NO if the neighbour is not connected or violates the quota,
1599 * #GNUNET_SYSERR if the connection is not fully up yet
1600 * @return how long to wait before reading more from this sender
1602 struct GNUNET_TIME_Relative
1603 GST_neighbours_calculate_receive_delay (const struct GNUNET_PeerIdentity
1604 *sender, ssize_t size, int *do_forward)
1606 struct NeighbourMapEntry *n;
1607 struct GNUNET_TIME_Relative ret;
1609 if (NULL == neighbours)
1611 *do_forward = GNUNET_NO;
1612 return GNUNET_TIME_UNIT_FOREVER_REL; /* This can happen during shutdown */
1614 if (NULL == (n = lookup_neighbour (sender)))
1616 GST_neighbours_try_connect (sender);
1617 if (NULL == (n = lookup_neighbour (sender)))
1619 GNUNET_STATISTICS_update (GST_stats,
1621 ("# messages discarded due to lack of neighbour record"),
1623 *do_forward = GNUNET_NO;
1624 return GNUNET_TIME_UNIT_ZERO;
1627 if (! test_connected (n))
1629 *do_forward = GNUNET_SYSERR;
1630 return GNUNET_TIME_UNIT_ZERO;
1632 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, size))
1634 n->quota_violation_count++;
1635 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1636 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
1637 n->in_tracker.available_bytes_per_s__,
1638 n->quota_violation_count);
1639 /* Discount 32k per violation */
1640 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, -32 * 1024);
1644 if (n->quota_violation_count > 0)
1646 /* try to add 32k back */
1647 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, 32 * 1024);
1648 n->quota_violation_count--;
1651 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
1653 GNUNET_STATISTICS_update (GST_stats,
1655 ("# bandwidth quota violations by other peers"),
1657 *do_forward = GNUNET_NO;
1658 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
1660 *do_forward = GNUNET_YES;
1661 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 32 * 1024);
1662 if (ret.rel_value_us > 0)
1664 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1665 "Throttling read (%lld bytes excess at %u b/s), waiting %s before reading more.\n",
1666 (long long) n->in_tracker.consumption_since_last_update__,
1667 (unsigned int) n->in_tracker.available_bytes_per_s__,
1668 GNUNET_STRINGS_relative_time_to_string (ret, GNUNET_YES));
1669 GNUNET_STATISTICS_update (GST_stats,
1670 gettext_noop ("# ms throttling suggested"),
1671 (int64_t) ret.rel_value_us / 1000LL,
1679 * Transmit a message to the given target using the active connection.
1681 * @param target destination
1682 * @param msg message to send
1683 * @param msg_size number of bytes in msg
1684 * @param timeout when to fail with timeout
1685 * @param cont function to call when done
1686 * @param cont_cls closure for @a cont
1689 GST_neighbours_send (const struct GNUNET_PeerIdentity *target,
1692 struct GNUNET_TIME_Relative timeout,
1693 GST_NeighbourSendContinuation cont,
1696 struct NeighbourMapEntry *n;
1697 struct MessageQueue *mq;
1699 /* All ove these cases should never happen; they are all API violations.
1700 But we check anyway, just to be sure. */
1701 if (NULL == (n = lookup_neighbour (target)))
1705 cont (cont_cls, GNUNET_SYSERR, msg_size, 0);
1708 if (GNUNET_YES != test_connected (n))
1712 cont (cont_cls, GNUNET_SYSERR, msg_size, 0);
1715 bytes_in_send_queue += msg_size;
1716 GNUNET_STATISTICS_set (GST_stats,
1718 ("# bytes in message queue for other peers"),
1719 bytes_in_send_queue, GNUNET_NO);
1720 mq = GNUNET_malloc (sizeof (struct MessageQueue) + msg_size);
1722 mq->cont_cls = cont_cls;
1723 memcpy (&mq[1], msg, msg_size);
1724 mq->message_buf = (const char *) &mq[1];
1725 mq->message_buf_size = msg_size;
1726 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1728 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Enqueueing %u bytes to send to peer %s\n",
1729 msg_size, GNUNET_i2s (target));
1731 GNUNET_CONTAINER_DLL_insert_tail (n->messages_head, n->messages_tail, mq);
1732 if (NULL != n->task)
1733 GNUNET_SCHEDULER_cancel (n->task);
1734 n->task = GNUNET_SCHEDULER_add_now (&master_task, n);
1739 * Continuation called from our attempt to transmitted our
1740 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN to the specified @a
1741 * target. Continue processing based on the @a result. Specifically,
1742 * if we failed to transmit, discard the address we used.
1745 * @param target which peer received the transmission
1746 * @param result #GNUNET_OK if sending worked
1747 * @param size_payload how many bytes of payload were sent (ignored)
1748 * @param size_on_wire how much bandwidth was consumed on the wire (ignored)
1751 send_session_syn_cont (void *cls,
1752 const struct GNUNET_PeerIdentity *target,
1754 size_t size_payload,
1755 size_t size_on_wire)
1757 struct NeighbourMapEntry *n;
1759 n = lookup_neighbour (target);
1762 /* SYN continuation was called after neighbor was freed,
1763 * for example due to a time out for the state or the session
1764 * used was already terminated: nothing to do here... */
1768 if ( (GNUNET_TRANSPORT_PS_SYN_SENT != n->state) &&
1769 (GNUNET_TRANSPORT_PS_RECONNECT_SENT != n->state) &&
1770 (GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT != n->state))
1772 /* SYN continuation was called after neighbor changed state,
1773 * for example due to a time out for the state or the session
1774 * used was already terminated: nothing to do here... */
1777 if (GNUNET_OK == result)
1780 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1781 _("Failed to send SYN message to peer `%s'\n"),
1782 GNUNET_i2s (target));
1784 case GNUNET_TRANSPORT_PS_SYN_SENT:
1785 /* Remove address and request an additional one */
1786 unset_primary_address (n);
1787 set_state_and_timeout (n,
1788 GNUNET_TRANSPORT_PS_INIT_ATS,
1789 GNUNET_TIME_relative_to_absolute (FAST_RECONNECT_TIMEOUT));
1791 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
1792 /* Remove address and request an additional one */
1793 unset_primary_address (n);
1794 set_state_and_timeout (n,
1795 GNUNET_TRANSPORT_PS_RECONNECT_ATS,
1796 GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT));
1798 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
1799 /* Remove address and request and go back to primary address */
1800 GNUNET_STATISTICS_update (GST_stats,
1801 gettext_noop ("# Failed attempts to switch addresses (failed to send SYN CONT)"),
1804 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1805 "Switch failed, cleaning up alternative address\n");
1806 free_address (&n->alternative_address);
1807 set_state_and_timeout (n,
1808 GNUNET_TRANSPORT_PS_CONNECTED,
1809 GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT));
1812 disconnect_neighbour (n);
1819 * Send a SYN message via the given address.
1821 * @param na address to use
1824 send_syn (struct NeighbourAddress *na)
1826 struct GNUNET_TRANSPORT_PluginFunctions *papi;
1827 struct TransportSynMessage connect_msg;
1828 struct NeighbourMapEntry *n;
1830 GNUNET_assert (NULL != na->session);
1831 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1832 "Sending SYN message to peer `%s' at %s\n",
1833 GNUNET_i2s (&na->address->peer),
1834 GST_plugins_a2s (na->address));
1836 papi = GST_plugins_find (na->address->transport_name);
1837 GNUNET_assert (NULL != papi);
1838 GNUNET_STATISTICS_update (GST_stats,
1840 ("# SYN messages sent"),
1842 na->connect_timestamp = GNUNET_TIME_absolute_get ();
1843 connect_msg.header.size = htons (sizeof (struct TransportSynMessage));
1844 connect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN);
1845 connect_msg.reserved = htonl (0);
1846 connect_msg.timestamp = GNUNET_TIME_absolute_hton (na->connect_timestamp);
1848 papi->send (papi->cls,
1850 (const char *) &connect_msg,
1851 sizeof (struct TransportSynMessage),
1853 SETUP_CONNECTION_TIMEOUT,
1854 &send_session_syn_cont, NULL))
1856 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1857 _("Failed to transmit SYN message to %s\n"),
1858 GST_plugins_a2s (na->address));
1859 n = lookup_neighbour (&na->address->peer);
1866 case GNUNET_TRANSPORT_PS_SYN_SENT:
1867 /* Remove address and request and additional one */
1868 GNUNET_assert (na == &n->primary_address);
1869 unset_primary_address (n);
1870 set_state_and_timeout (n,
1871 GNUNET_TRANSPORT_PS_INIT_ATS,
1872 GNUNET_TIME_relative_to_absolute (FAST_RECONNECT_TIMEOUT));
1873 /* Hard failure to send the SYN message with this address:
1874 Destroy address and session */
1876 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
1877 /* Remove address and request an additional one */
1878 GNUNET_assert (na == &n->primary_address);
1879 unset_primary_address (n);
1880 set_state_and_timeout (n,
1881 GNUNET_TRANSPORT_PS_RECONNECT_ATS,
1882 GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT));
1884 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
1885 GNUNET_assert (na == &n->alternative_address);
1886 GNUNET_STATISTICS_update (GST_stats,
1887 gettext_noop ("# Failed attempts to switch addresses (failed to send SYN)"),
1890 /* Remove address and request an additional one */
1891 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1892 "Switch failed, cleaning up alternative address\n");
1893 free_address (&n->alternative_address);
1894 set_state_and_timeout (n,
1895 GNUNET_TRANSPORT_PS_CONNECTED,
1896 GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT));
1900 disconnect_neighbour (n);
1904 GST_neighbours_notify_data_sent (na->address,
1906 sizeof (struct TransportSynMessage));
1911 * Continuation called from our attempt to transmitted our
1912 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN_ACK to the specified @a
1913 * target. Continue processing based on the @a result. Specifically,
1914 * if we failed to transmit, discard the address we used.
1917 * @param target which peer received the transmission
1918 * @param result #GNUNET_OK if sending worked
1919 * @param size_payload how many bytes of payload were sent (ignored)
1920 * @param size_on_wire how much bandwidth was consumed on the wire (ignored)
1923 send_session_syn_ack_cont (void *cls,
1924 const struct GNUNET_PeerIdentity *target,
1926 size_t size_payload,
1927 size_t size_on_wire)
1929 struct NeighbourMapEntry *n;
1931 n = lookup_neighbour (target);
1934 /* SYN_ACK continuation was called after neighbor was freed,
1935 * for example due to a time out for the state or the session
1936 * used was already terminated: nothing to do here... */
1940 if (GNUNET_TRANSPORT_PS_SYN_RECV_ACK != n->state)
1942 /* SYN_ACK continuation was called after neighbor changed state,
1943 * for example due to a time out for the state or the session
1944 * used was already terminated: nothing to do here... */
1947 if (GNUNET_OK == result)
1950 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1951 _("Failed to send SYN_ACK message to peer `%s' using address `%s'\n"),
1952 GNUNET_i2s (target),
1953 GST_plugins_a2s (n->primary_address.address));
1955 /* Remove address and request and additional one */
1956 /* FIXME: what if the neighbour's primary address
1957 changed in the meantime? Might want to instead
1958 pass "something" around in closure to be sure. */
1959 unset_primary_address (n);
1960 n->ack_state = ACK_SEND_SYN_ACK;
1961 set_state_and_timeout (n,
1962 GNUNET_TRANSPORT_PS_SYN_RECV_ATS,
1963 GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT));
1968 * Send a SYN_ACK message via the given address.
1970 * @param na address and session to use
1971 * @param timestamp timestamp to use for the ACK message
1972 * @return #GNUNET_SYSERR if sending immediately failed, #GNUNET_OK otherwise
1975 send_syn_ack_message (struct NeighbourAddress *na,
1976 struct GNUNET_TIME_Absolute timestamp)
1978 const struct GNUNET_HELLO_Address *address = na->address;
1979 struct Session *session = na->session;
1980 struct GNUNET_TRANSPORT_PluginFunctions *papi;
1981 struct TransportSynMessage connect_msg;
1982 struct NeighbourMapEntry *n;
1984 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1985 "Sending SYN_ACK to peer `%s'\n",
1986 GNUNET_i2s (&address->peer));
1988 if (NULL == (papi = GST_plugins_find (address->transport_name)))
1993 if (NULL == session)
1994 session = papi->get_session (papi->cls,
1996 if (NULL == session)
2001 GST_ats_new_session (address,
2003 GNUNET_STATISTICS_update (GST_stats,
2005 ("# SYN_ACK messages sent"),
2007 connect_msg.header.size = htons (sizeof (struct TransportSynMessage));
2008 connect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN_ACK);
2009 connect_msg.reserved = htonl (0);
2010 connect_msg.timestamp = GNUNET_TIME_absolute_hton (timestamp);
2012 if (GNUNET_SYSERR ==
2013 papi->send (papi->cls,
2015 (const char *) &connect_msg,
2016 sizeof (struct TransportSynMessage),
2018 GNUNET_TIME_UNIT_FOREVER_REL,
2019 &send_session_syn_ack_cont, NULL))
2021 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2022 _("Failed to transmit SYN_ACK message to %s\n"),
2023 GST_plugins_a2s (address));
2025 n = lookup_neighbour (&address->peer);
2031 /* Remove address and request and additional one */
2032 unset_primary_address (n);
2033 n->ack_state = ACK_SEND_SYN_ACK;
2034 set_state_and_timeout (n,
2035 GNUNET_TRANSPORT_PS_SYN_RECV_ATS,
2036 GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT));
2043 * Function called by the bandwidth tracker for a peer whenever
2044 * the tracker's state changed such that we need to recalculate
2045 * the delay for flow control. We calculate the latest delay
2046 * and inform the plugin (if applicable).
2048 * @param cls the `struct NeighbourMapEntry` to update calculations for
2051 inbound_bw_tracker_update (void *cls)
2053 struct NeighbourMapEntry *n = cls;
2054 struct GNUNET_TRANSPORT_PluginFunctions *papi;
2055 struct GNUNET_TIME_Relative delay;
2058 if (NULL == n->primary_address.address)
2059 return; /* not active, ignore */
2060 papi = GST_plugins_find (n->primary_address.address->transport_name);
2061 GNUNET_assert (NULL != papi);
2062 if (NULL == papi->update_inbound_delay)
2064 delay = GST_neighbours_calculate_receive_delay (&n->id,
2067 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2068 "New inbound delay for peer `%s' is %llu ms\n",
2069 GNUNET_i2s (&n->id),
2070 delay.rel_value_us / 1000);
2071 papi->update_inbound_delay (papi->cls,
2073 n->primary_address.session,
2079 * Create a fresh entry in the neighbour map for the given peer
2081 * @param peer peer to create an entry for
2082 * @return new neighbour map entry
2084 static struct NeighbourMapEntry *
2085 setup_neighbour (const struct GNUNET_PeerIdentity *peer)
2087 struct NeighbourMapEntry *n;
2089 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2090 "Creating new neighbour entry for `%s'\n",
2092 n = GNUNET_new (struct NeighbourMapEntry);
2094 n->ack_state = ACK_UNDEFINED;
2095 n->last_util_transmission = GNUNET_TIME_absolute_get();
2096 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
2097 &inbound_bw_tracker_update,
2099 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
2100 MAX_BANDWIDTH_CARRY_S);
2101 n->task = GNUNET_SCHEDULER_add_now (&master_task, n);
2102 set_state_and_timeout (n,
2103 GNUNET_TRANSPORT_PS_NOT_CONNECTED,
2104 GNUNET_TIME_UNIT_FOREVER_ABS);
2105 GNUNET_assert (GNUNET_OK ==
2106 GNUNET_CONTAINER_multipeermap_put (neighbours,
2108 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2109 n->suggest_handle = GNUNET_ATS_connectivity_suggest (GST_ats_connect,
2117 * Entry in a DLL we use to keep track of pending blacklist checks.
2119 struct BlacklistCheckSwitchContext
2124 struct BlacklistCheckSwitchContext *prev;
2129 struct BlacklistCheckSwitchContext *next;
2132 * Handle to the blacklist check we are performing.
2134 struct GST_BlacklistCheck *blc;
2137 * Address we are asking the blacklist subsystem about.
2139 struct GNUNET_HELLO_Address *address;
2142 * Session we should use in conjunction with @e address, can be NULL.
2144 struct Session *session;
2147 * Inbound bandwidth that was assigned to @e address.
2149 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
2152 * Outbound bandwidth that was assigned to @e address.
2154 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
2159 * Black list check result for try_connect call
2160 * If connection to the peer is allowed request adddress and
2162 * @param cls blc_ctx bl context
2163 * @param peer the peer
2164 * @param result the result
2167 try_connect_bl_check_cont (void *cls,
2168 const struct GNUNET_PeerIdentity *peer,
2171 struct BlacklistCheckSwitchContext *blc_ctx = cls;
2172 struct NeighbourMapEntry *n;
2174 GNUNET_CONTAINER_DLL_remove (pending_bc_head,
2177 GNUNET_free (blc_ctx);
2178 if (GNUNET_OK != result)
2180 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2181 _("Blacklisting disapproved to connect to peer `%s'\n"),
2186 /* Setup a new neighbour */
2187 if (NULL != lookup_neighbour(peer))
2188 return; /* The neighbor was created in the meantime while waited for BL clients */
2190 n = setup_neighbour (peer);
2192 /* Request address suggestions for this peer */
2193 set_state_and_timeout (n,
2194 GNUNET_TRANSPORT_PS_INIT_ATS,
2195 GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT));
2200 * Try to create a connection to the given target (eventually).
2202 * @param target peer to try to connect to
2205 GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target)
2207 struct NeighbourMapEntry *n;
2208 struct GST_BlacklistCheck *blc;
2209 struct BlacklistCheckSwitchContext *blc_ctx;
2211 if (NULL == neighbours)
2213 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2214 "Asked to connect to peer `%s' during shutdown\n",
2215 GNUNET_i2s (target));
2216 return; /* during shutdown, do nothing */
2218 n = lookup_neighbour (target);
2219 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2220 "Asked to connect to peer `%s' (state: %s)\n",
2221 GNUNET_i2s (target),
2222 (NULL != n) ? GNUNET_TRANSPORT_ps2s(n->state) : "NEW PEER");
2227 case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
2228 /* this should not be possible */
2232 case GNUNET_TRANSPORT_PS_INIT_ATS:
2233 case GNUNET_TRANSPORT_PS_SYN_SENT:
2234 case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
2235 case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
2236 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2237 "Ignoring request to try to connect to `%s', already trying!\n",
2238 GNUNET_i2s (target));
2239 return; /* already trying */
2240 case GNUNET_TRANSPORT_PS_CONNECTED:
2241 case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
2242 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
2243 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
2244 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2245 "Ignoring request to try to connect, already connected to `%s'!\n",
2246 GNUNET_i2s (target));
2247 return; /* already connected */
2248 case GNUNET_TRANSPORT_PS_DISCONNECT:
2249 /* get rid of remains, ready to re-try immediately */
2252 case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
2253 /* should not be possible */
2257 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2258 "Unhandled state `%s'\n",
2259 GNUNET_TRANSPORT_ps2s (n->state));
2266 /* Do blacklist check if connecting to this peer is allowed */
2267 blc_ctx = GNUNET_new (struct BlacklistCheckSwitchContext);
2268 GNUNET_CONTAINER_DLL_insert (pending_bc_head,
2273 (blc = GST_blacklist_test_allowed (target,
2275 &try_connect_bl_check_cont,
2284 * We received a 'SYN' message from the other peer.
2285 * Consider switching to it.
2287 * @param message possibly a 'struct TransportSynMessage' (check format)
2288 * @param peer identity of the peer to switch the address for
2289 * @return #GNUNET_OK if the message was fine, #GNUNET_SYSERR on serious error
2292 GST_neighbours_handle_session_syn (const struct GNUNET_MessageHeader *message,
2293 const struct GNUNET_PeerIdentity *peer)
2295 const struct TransportSynMessage *scm;
2296 struct NeighbourMapEntry *n;
2297 struct GNUNET_TIME_Absolute ts;
2299 if (ntohs (message->size) != sizeof (struct TransportSynMessage))
2301 GNUNET_break_op (0);
2302 return GNUNET_SYSERR;
2304 GNUNET_STATISTICS_update (GST_stats,
2306 ("# SYN messages received"),
2308 if (NULL == neighbours)
2310 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2311 _("SYN request from peer `%s' ignored due impending shutdown\n"),
2313 return GNUNET_OK; /* we're shutting down */
2315 scm = (const struct TransportSynMessage *) message;
2316 GNUNET_break_op (0 == ntohl (scm->reserved));
2317 ts = GNUNET_TIME_absolute_ntoh (scm->timestamp);
2318 n = lookup_neighbour (peer);
2321 /* This is a new neighbour and set to not connected */
2322 n = setup_neighbour (peer);
2325 /* Remember this SYN message in neighbour */
2326 n->ack_state = ACK_SEND_SYN_ACK;
2327 n->connect_ack_timestamp = ts;
2329 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2330 "Received SYN for peer `%s' in state %s/%s\n",
2332 GNUNET_TRANSPORT_ps2s (n->state),
2333 print_ack_state (n->ack_state));
2337 case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
2338 /* Request an address from ATS to send SYN_ACK to this peer */
2339 set_state_and_timeout (n,
2340 GNUNET_TRANSPORT_PS_SYN_RECV_ATS,
2341 GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT));
2343 case GNUNET_TRANSPORT_PS_INIT_ATS:
2344 /* SYN message takes priority over us asking ATS for address:
2345 * Wait for ATS to suggest an address and send SYN_ACK */
2346 set_state_and_timeout (n,
2347 GNUNET_TRANSPORT_PS_SYN_RECV_ATS,
2348 GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT));
2350 case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
2351 /* We already wait for an address to send an SYN_ACK */
2353 case GNUNET_TRANSPORT_PS_SYN_SENT:
2354 case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
2355 /* Send ACK immediately */
2356 n->ack_state = ACK_SEND_ACK;
2357 send_syn_ack_message (&n->primary_address,
2360 case GNUNET_TRANSPORT_PS_CONNECTED:
2361 /* we are already connected and can thus send the ACK immediately */
2362 GNUNET_assert (NULL != n->primary_address.address);
2363 GNUNET_assert (NULL != n->primary_address.session);
2364 n->ack_state = ACK_SEND_ACK;
2365 send_syn_ack_message (&n->primary_address,
2368 case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
2369 /* We wait for ATS address suggestion */
2371 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
2372 /* We received a SYN message while waiting for a SYN_ACK in fast
2373 * reconnect. Send SYN_ACK immediately */
2374 n->ack_state = ACK_SEND_ACK;
2375 send_syn_ack_message (&n->primary_address,
2376 n->connect_ack_timestamp);
2378 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
2379 /* We are already connected and can thus send the ACK immediately;
2380 still, it can never hurt to have an alternative address, so also
2381 tell ATS about it */
2382 GNUNET_assert (NULL != n->primary_address.address);
2383 GNUNET_assert (NULL != n->primary_address.session);
2384 n->ack_state = ACK_SEND_ACK;
2385 send_syn_ack_message (&n->primary_address,
2388 case GNUNET_TRANSPORT_PS_DISCONNECT:
2389 /* Get rid of remains and re-try */
2391 n = setup_neighbour (peer);
2392 /* Remember the SYN time stamp for ACK message */
2393 n->ack_state = ACK_SEND_SYN_ACK;
2394 n->connect_ack_timestamp = ts;
2395 /* Request an address for the peer */
2396 set_state_and_timeout (n,
2397 GNUNET_TRANSPORT_PS_SYN_RECV_ATS,
2398 GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT));
2400 case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
2401 /* should not be possible */
2405 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2406 "Unhandled state `%s'\n",
2407 GNUNET_TRANSPORT_ps2s (n->state));
2409 return GNUNET_SYSERR;
2416 * Check if the given @a address is the same that we are already
2417 * using for the respective neighbour. If so, update the bandwidth
2418 * assignment and possibly the session and return #GNUNET_OK.
2419 * If the new address is different from what the neighbour is
2420 * using right now, return #GNUNET_NO.
2422 * @param address address of the other peer,
2423 * @param session session to use or NULL if transport should initiate a session
2424 * @param bandwidth_in inbound quota to be used when connection is up,
2425 * 0 to disconnect from peer
2426 * @param bandwidth_out outbound quota to be used when connection is up,
2427 * 0 to disconnect from peer
2428 * @return #GNUNET_OK if we were able to just update the bandwidth and session,
2429 * #GNUNET_NO if more extensive changes are required (address changed)
2432 try_run_fast_ats_update (const struct GNUNET_HELLO_Address *address,
2433 struct Session *session,
2434 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
2435 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
2437 struct NeighbourMapEntry *n;
2439 n = lookup_neighbour (&address->peer);
2441 (NULL == n->primary_address.address) ||
2442 (0 != GNUNET_HELLO_address_cmp (address,
2443 n->primary_address.address)) )
2445 /* We are not really switching addresses, but merely adjusting
2446 session and/or bandwidth, can do fast ATS update! */
2447 if (session != n->primary_address.session)
2449 /* switch to a different session, but keeping same address; could
2450 happen if there is a 2nd inbound connection */
2451 n->primary_address.session = session;
2453 n->primary_address.bandwidth_in = bandwidth_in;
2454 n->primary_address.bandwidth_out = bandwidth_out;
2455 GST_neighbours_set_incoming_quota (&address->peer,
2457 send_outbound_quota (&address->peer,
2464 * We've been asked to switch addresses, and just now got the result
2465 * from the blacklist check to see if this is allowed.
2467 * @param cls the `struct BlacklistCheckSwitchContext` with
2468 * the information about the future address
2469 * @param peer the peer we may switch addresses on
2470 * @param result #GNUNET_NO if we are not allowed to use the new
2474 switch_address_bl_check_cont (void *cls,
2475 const struct GNUNET_PeerIdentity *peer,
2478 struct BlacklistCheckSwitchContext *blc_ctx = cls;
2479 struct GNUNET_TRANSPORT_PluginFunctions *papi;
2480 struct NeighbourMapEntry *n;
2482 if (result == GNUNET_NO)
2484 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2485 "Blacklist denied to switch to suggested address `%s' session %p for peer `%s'\n",
2486 GST_plugins_a2s (blc_ctx->address),
2488 GNUNET_i2s (&blc_ctx->address->peer));
2489 GNUNET_STATISTICS_update (GST_stats,
2490 "# ATS suggestions ignored (blacklist denied)",
2493 /* FIXME: tell plugin to force killing session here and now
2494 (note: _proper_ plugin API for this does not yet exist) */
2495 GST_ats_block_address (blc_ctx->address,
2500 papi = GST_plugins_find (blc_ctx->address->transport_name);
2501 GNUNET_assert (NULL != papi);
2503 if (NULL == blc_ctx->session)
2505 /* need to create a session, ATS only gave us an address */
2506 blc_ctx->session = papi->get_session (papi->cls,
2508 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2509 "Obtained new session for peer `%s' and address '%s': %p\n",
2510 GNUNET_i2s (&blc_ctx->address->peer),
2511 GST_plugins_a2s (blc_ctx->address),
2513 if (NULL != blc_ctx->session)
2514 GST_ats_new_session (blc_ctx->address,
2517 if (NULL == blc_ctx->session)
2519 /* session creation failed, bad!, fail! */
2520 GNUNET_STATISTICS_update (GST_stats,
2521 "# ATS suggestions ignored (failed to create session)",
2524 /* No session could be obtained, remove blacklist check and clean up */
2525 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2526 "Failed to obtain new session for peer `%s' and address '%s'\n",
2527 GNUNET_i2s (&blc_ctx->address->peer),
2528 GST_plugins_a2s (blc_ctx->address));
2529 GST_ats_block_address (blc_ctx->address,
2534 /* We did this check already before going into blacklist, but
2535 it is theoretically possible that the situation changed in
2536 the meantime, hence we check again here */
2538 try_run_fast_ats_update (blc_ctx->address,
2540 blc_ctx->bandwidth_in,
2541 blc_ctx->bandwidth_out))
2542 goto cleanup; /* was just a minor update, we're done */
2544 /* check if we also need to setup the neighbour entry */
2545 if (NULL == (n = lookup_neighbour (peer)))
2547 n = setup_neighbour (peer);
2548 n->state = GNUNET_TRANSPORT_PS_INIT_ATS;
2551 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2552 "Peer `%s' switches to address `%s'\n",
2553 GNUNET_i2s (&blc_ctx->address->peer),
2554 GST_plugins_a2s (blc_ctx->address));
2558 case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
2560 GST_ats_block_address (blc_ctx->address,
2564 case GNUNET_TRANSPORT_PS_INIT_ATS:
2565 /* We requested an address and ATS suggests one:
2566 * set primary address and send SYN message*/
2567 set_primary_address (n,
2570 blc_ctx->bandwidth_in,
2571 blc_ctx->bandwidth_out,
2573 if (ACK_SEND_SYN_ACK == n->ack_state)
2575 /* Send pending SYN_ACK message */
2576 n->ack_state = ACK_SEND_ACK;
2577 send_syn_ack_message (&n->primary_address,
2578 n->connect_ack_timestamp);
2580 set_state_and_timeout (n,
2581 GNUNET_TRANSPORT_PS_SYN_SENT,
2582 GNUNET_TIME_relative_to_absolute (SETUP_CONNECTION_TIMEOUT));
2583 send_syn (&n->primary_address);
2585 case GNUNET_TRANSPORT_PS_SYN_SENT:
2586 /* ATS suggested a new address while waiting for an SYN_ACK:
2587 * Switch and send new SYN */
2588 /* ATS suggests a different address, switch again */
2589 set_primary_address (n,
2592 blc_ctx->bandwidth_in,
2593 blc_ctx->bandwidth_out,
2595 if (ACK_SEND_SYN_ACK == n->ack_state)
2597 /* Send pending SYN_ACK message */
2598 n->ack_state = ACK_SEND_ACK;
2599 send_syn_ack_message (&n->primary_address,
2600 n->connect_ack_timestamp);
2602 set_state_and_timeout (n,
2603 GNUNET_TRANSPORT_PS_SYN_SENT,
2604 GNUNET_TIME_relative_to_absolute (SETUP_CONNECTION_TIMEOUT));
2605 send_syn (&n->primary_address);
2607 case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
2608 /* We requested an address and ATS suggests one:
2609 * set primary address and send SYN_ACK message*/
2610 set_primary_address (n,
2613 blc_ctx->bandwidth_in,
2614 blc_ctx->bandwidth_out,
2616 /* Send an ACK message as a response to the SYN msg */
2617 set_state_and_timeout (n,
2618 GNUNET_TRANSPORT_PS_SYN_RECV_ACK,
2619 GNUNET_TIME_relative_to_absolute (SETUP_CONNECTION_TIMEOUT));
2620 send_syn_ack_message (&n->primary_address,
2621 n->connect_ack_timestamp);
2622 if ( (ACK_SEND_SYN_ACK == n->ack_state) ||
2623 (ACK_UNDEFINED == n->ack_state) )
2624 n->ack_state = ACK_SEND_ACK;
2626 case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
2627 /* ATS asks us to switch while we were trying to connect; switch to new
2628 address and check blacklist again */
2629 if ( (ACK_SEND_SYN_ACK == n->ack_state) )
2631 n->ack_state = ACK_SEND_ACK;
2632 send_syn_ack_message (&n->primary_address,
2633 n->connect_ack_timestamp);
2635 set_primary_address (n,
2638 blc_ctx->bandwidth_in,
2639 blc_ctx->bandwidth_out,
2641 set_state_and_timeout (n,
2642 GNUNET_TRANSPORT_PS_SYN_RECV_ACK,
2643 GNUNET_TIME_relative_to_absolute (SETUP_CONNECTION_TIMEOUT));
2645 case GNUNET_TRANSPORT_PS_CONNECTED:
2646 GNUNET_assert (NULL != n->primary_address.address);
2647 GNUNET_assert (NULL != n->primary_address.session);
2648 GNUNET_break (n->primary_address.session != blc_ctx->session);
2649 /* ATS asks us to switch a life connection; see if we can get
2650 a SYN_ACK on it before we actually do this! */
2651 set_alternative_address (n,
2654 blc_ctx->bandwidth_in,
2655 blc_ctx->bandwidth_out);
2656 set_state_and_timeout (n,
2657 GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT,
2658 GNUNET_TIME_relative_to_absolute (SETUP_CONNECTION_TIMEOUT));
2659 GNUNET_STATISTICS_update (GST_stats,
2660 gettext_noop ("# Attempts to switch addresses"),
2663 send_syn (&n->alternative_address);
2665 case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
2666 set_primary_address (n,
2669 blc_ctx->bandwidth_in,
2670 blc_ctx->bandwidth_out,
2672 if (ACK_SEND_SYN_ACK == n->ack_state)
2674 /* Send pending SYN_ACK message */
2675 n->ack_state = ACK_SEND_ACK;
2676 send_syn_ack_message (&n->primary_address,
2677 n->connect_ack_timestamp);
2679 set_state_and_timeout (n,
2680 GNUNET_TRANSPORT_PS_RECONNECT_SENT,
2681 GNUNET_TIME_relative_to_absolute (FAST_RECONNECT_TIMEOUT));
2682 send_syn (&n->primary_address);
2684 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
2685 /* ATS asks us to switch while we were trying to reconnect; switch to new
2686 address and send SYN again */
2687 set_primary_address (n,
2690 blc_ctx->bandwidth_in,
2691 blc_ctx->bandwidth_out,
2693 set_state_and_timeout (n,
2694 GNUNET_TRANSPORT_PS_RECONNECT_SENT,
2695 GNUNET_TIME_relative_to_absolute (FAST_RECONNECT_TIMEOUT));
2696 send_syn (&n->primary_address);
2698 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
2699 if ( (0 == GNUNET_HELLO_address_cmp (n->primary_address.address,
2700 blc_ctx->address)) &&
2701 (n->primary_address.session == blc_ctx->session) )
2703 /* ATS switches back to still-active session */
2704 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2705 "ATS double-switched, cleaning up alternative address\n");
2706 free_address (&n->alternative_address);
2707 set_state_and_timeout (n,
2708 GNUNET_TRANSPORT_PS_CONNECTED,
2712 /* ATS asks us to switch a life connection, send */
2713 set_alternative_address (n,
2716 blc_ctx->bandwidth_in,
2717 blc_ctx->bandwidth_out);
2718 set_state_and_timeout (n,
2719 GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT,
2720 GNUNET_TIME_relative_to_absolute (SETUP_CONNECTION_TIMEOUT));
2721 send_syn (&n->alternative_address);
2723 case GNUNET_TRANSPORT_PS_DISCONNECT:
2724 /* not going to switch addresses while disconnecting */
2725 GNUNET_STATISTICS_update (GST_stats,
2726 "# ATS suggestion ignored (disconnecting)",
2730 case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
2734 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2735 "Unhandled state `%s'\n",
2736 GNUNET_TRANSPORT_ps2s (n->state));
2741 GNUNET_CONTAINER_DLL_remove (pending_bc_head,
2744 GNUNET_HELLO_address_free (blc_ctx->address);
2745 GNUNET_free (blc_ctx);
2750 * For the given peer, switch to this address.
2752 * Before accepting this addresses and actively using it, a blacklist check
2755 * If any check fails or the suggestion can somehow not be followed, we
2756 * MUST call #GST_ats_block_address() to tell ATS that the suggestion
2757 * could not be satisfied and force ATS to do something else.
2759 * @param address address of the other peer,
2760 * @param session session to use or NULL if transport should initiate a session
2761 * @param bandwidth_in inbound quota to be used when connection is up,
2762 * 0 to disconnect from peer
2763 * @param bandwidth_out outbound quota to be used when connection is up,
2764 * 0 to disconnect from peer
2767 GST_neighbours_switch_to_address (const struct GNUNET_HELLO_Address *address,
2768 struct Session *session,
2769 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
2770 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
2772 struct GST_BlacklistCheck *blc;
2773 struct BlacklistCheckSwitchContext *blc_ctx;
2775 GNUNET_assert (NULL != address->transport_name);
2777 try_run_fast_ats_update (address,
2783 /* Check if plugin is available */
2784 if (NULL == (GST_plugins_find (address->transport_name)))
2786 /* we don't have the plugin for this address */
2788 GST_ats_block_address (address,
2792 if ((NULL == session) &&
2793 (GNUNET_HELLO_address_check_option (address,
2794 GNUNET_HELLO_ADDRESS_INFO_INBOUND)))
2796 /* This is a inbound address and we do not have a session to use! */
2798 GST_ats_block_address (address,
2803 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2804 "ATS suggests address '%s' for peer `%s'\n",
2805 GST_plugins_a2s (address),
2806 GNUNET_i2s (&address->peer));
2808 /* Perform blacklist check */
2809 blc_ctx = GNUNET_new (struct BlacklistCheckSwitchContext);
2810 blc_ctx->address = GNUNET_HELLO_address_copy (address);
2811 blc_ctx->session = session;
2812 blc_ctx->bandwidth_in = bandwidth_in;
2813 blc_ctx->bandwidth_out = bandwidth_out;
2814 GNUNET_CONTAINER_DLL_insert (pending_bc_head,
2817 if (NULL != (blc = GST_blacklist_test_allowed (&address->peer,
2818 address->transport_name,
2819 &switch_address_bl_check_cont,
2828 * Function called to send network utilization data to ATS for
2829 * each active connection.
2832 * @param key peer we send utilization data for
2833 * @param value the `struct NeighbourMapEntry *` with data to send
2834 * @return #GNUNET_OK (continue to iterate)
2837 send_utilization_data (void *cls,
2838 const struct GNUNET_PeerIdentity *key,
2841 struct NeighbourMapEntry *n = value;
2842 struct GNUNET_ATS_Information atsi[4];
2844 uint32_t bps_pl_out;
2847 struct GNUNET_TIME_Relative delta;
2849 if (GNUNET_YES != test_connected (n))
2851 delta = GNUNET_TIME_absolute_get_difference (n->last_util_transmission,
2852 GNUNET_TIME_absolute_get ());
2856 if ((0 != n->util_payload_bytes_recv) && (0 != delta.rel_value_us))
2857 bps_pl_in = (1000LL * 1000LL * n->util_payload_bytes_recv) / (delta.rel_value_us);
2859 if ((0 != n->util_payload_bytes_sent) && (0 != delta.rel_value_us))
2860 bps_pl_out = (1000LL * 1000LL * n->util_payload_bytes_sent) / delta.rel_value_us;
2861 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2862 "`%s' payload: received %u Bytes/s, sent %u Bytes/s\n",
2867 if ((0 != n->util_total_bytes_recv) && (0 != delta.rel_value_us))
2868 bps_in = (1000LL * 1000LL * n->util_total_bytes_recv) / (delta.rel_value_us);
2870 if ((0 != n->util_total_bytes_sent) && (0 != delta.rel_value_us))
2871 bps_out = (1000LL * 1000LL * n->util_total_bytes_sent) / delta.rel_value_us;
2874 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2875 "`%s' total: received %u Bytes/s, sent %u Bytes/s\n",
2879 atsi[0].type = htonl (GNUNET_ATS_UTILIZATION_OUT);
2880 atsi[0].value = htonl (bps_out);
2881 atsi[1].type = htonl (GNUNET_ATS_UTILIZATION_IN);
2882 atsi[1].value = htonl (bps_in);
2884 atsi[2].type = htonl (GNUNET_ATS_UTILIZATION_PAYLOAD_OUT);
2885 atsi[2].value = htonl (bps_pl_out);
2886 atsi[3].type = htonl (GNUNET_ATS_UTILIZATION_PAYLOAD_IN);
2887 atsi[3].value = htonl (bps_pl_in);
2889 GST_ats_update_metrics (n->primary_address.address,
2890 n->primary_address.session,
2892 n->util_payload_bytes_recv = 0;
2893 n->util_payload_bytes_sent = 0;
2894 n->util_total_bytes_recv = 0;
2895 n->util_total_bytes_sent = 0;
2896 n->last_util_transmission = GNUNET_TIME_absolute_get ();
2902 * Task transmitting utilization in a regular interval
2904 * @param cls the 'struct NeighbourMapEntry' for which we are running
2905 * @param tc scheduler context (unused)
2908 utilization_transmission (void *cls,
2909 const struct GNUNET_SCHEDULER_TaskContext *tc)
2911 util_transmission_tk = NULL;
2912 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
2913 &send_utilization_data,
2915 util_transmission_tk
2916 = GNUNET_SCHEDULER_add_delayed (UTIL_TRANSMISSION_INTERVAL,
2917 &utilization_transmission,
2923 * Track information about data we received from the
2924 * given address (used to notify ATS about our utilization
2925 * of allocated resources).
2927 * @param address the address we got data from
2928 * @param message the message we received (really only the size is used)
2931 GST_neighbours_notify_data_recv (const struct GNUNET_HELLO_Address *address,
2932 const struct GNUNET_MessageHeader *message)
2934 struct NeighbourMapEntry *n;
2936 n = lookup_neighbour (&address->peer);
2939 n->util_total_bytes_recv += ntohs (message->size);
2944 * Track information about payload (useful data) we received from the
2945 * given address (used to notify ATS about our utilization of
2946 * allocated resources).
2948 * @param address the address we got data from
2949 * @param message the message we received (really only the size is used)
2952 GST_neighbours_notify_payload_recv (const struct GNUNET_HELLO_Address *address,
2953 const struct GNUNET_MessageHeader *message)
2955 struct NeighbourMapEntry *n;
2957 n = lookup_neighbour (&address->peer);
2960 n->util_payload_bytes_recv += ntohs (message->size);
2965 * Track information about data we transmitted using the given @a
2966 * address and @a session (used to notify ATS about our utilization of
2967 * allocated resources).
2969 * @param address the address we transmitted data to
2970 * @param session session we used to transmit data
2971 * @param message the message we sent (really only the size is used)
2974 GST_neighbours_notify_data_sent (const struct GNUNET_HELLO_Address *address,
2975 struct Session *session,
2978 struct NeighbourMapEntry *n;
2980 n = lookup_neighbour (&address->peer);
2983 if (n->primary_address.session != session)
2985 n->util_total_bytes_sent += size;
2990 * Track information about payload (useful data) we transmitted using the
2991 * given address (used to notify ATS about our utilization of
2992 * allocated resources).
2994 * @param address the address we transmitted data to
2995 * @param message the message we sent (really only the size is used)
2998 GST_neighbours_notify_payload_sent (const struct GNUNET_PeerIdentity *peer,
3001 struct NeighbourMapEntry *n;
3003 n = lookup_neighbour (peer);
3006 n->util_payload_bytes_sent += size;
3011 * Master task run for every neighbour. Performs all of the time-related
3012 * activities (keep alive, send next message, disconnect if idle, finish
3013 * clean up after disconnect).
3015 * @param cls the 'struct NeighbourMapEntry' for which we are running
3016 * @param tc scheduler context (unused)
3019 master_task (void *cls,
3020 const struct GNUNET_SCHEDULER_TaskContext *tc)
3022 struct NeighbourMapEntry *n = cls;
3023 struct GNUNET_TIME_Relative delay;
3026 delay = GNUNET_TIME_absolute_get_remaining (n->timeout);
3027 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3028 "Master task runs for neighbour `%s' in state %s with timeout in %s\n",
3029 GNUNET_i2s (&n->id),
3030 GNUNET_TRANSPORT_ps2s(n->state),
3031 GNUNET_STRINGS_relative_time_to_string (delay,
3035 case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
3036 /* invalid state for master task, clean up */
3040 case GNUNET_TRANSPORT_PS_INIT_ATS:
3041 if (0 == delay.rel_value_us)
3043 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3044 "Connection to `%s' timed out waiting for ATS to provide address\n",
3045 GNUNET_i2s (&n->id));
3050 case GNUNET_TRANSPORT_PS_SYN_SENT:
3051 if (0 == delay.rel_value_us)
3053 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3054 "Connection to `%s' timed out waiting for other peer to send SYN_ACK\n",
3055 GNUNET_i2s (&n->id));
3056 /* Remove address and request and additional one */
3057 unset_primary_address (n);
3058 set_state_and_timeout (n,
3059 GNUNET_TRANSPORT_PS_INIT_ATS,
3060 GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT));
3064 case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
3065 if (0 == delay.rel_value_us)
3067 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3068 "Connection to `%s' timed out waiting ATS to provide address to use for SYN_ACK\n",
3069 GNUNET_i2s (&n->id));
3074 case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
3075 if (0 == delay.rel_value_us)
3077 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3078 "Connection to `%s' timed out waiting for other peer to send ACK\n",
3079 GNUNET_i2s (&n->id));
3080 disconnect_neighbour (n);
3084 case GNUNET_TRANSPORT_PS_CONNECTED:
3085 if (0 == delay.rel_value_us)
3087 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3088 "Connection to `%s' timed out, missing KEEPALIVE_RESPONSEs\n",
3089 GNUNET_i2s (&n->id));
3090 disconnect_neighbour (n);
3093 try_transmission_to_peer (n);
3096 case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
3097 if (0 == delay.rel_value_us)
3099 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3100 "Connection to `%s' timed out, waiting for ATS replacement address\n",
3101 GNUNET_i2s (&n->id));
3102 disconnect_neighbour (n);
3106 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
3107 if (0 == delay.rel_value_us)
3109 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3110 "Connection to `%s' timed out, waiting for other peer to SYN_ACK replacement address\n",
3111 GNUNET_i2s (&n->id));
3112 disconnect_neighbour (n);
3116 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
3117 if (0 == delay.rel_value_us)
3119 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3120 "Switch failed, cleaning up alternative address\n");
3121 free_address (&n->alternative_address);
3122 set_state_and_timeout (n,
3123 GNUNET_TRANSPORT_PS_CONNECTED,
3124 GNUNET_TIME_relative_to_absolute (SETUP_CONNECTION_TIMEOUT));
3126 try_transmission_to_peer (n);
3129 case GNUNET_TRANSPORT_PS_DISCONNECT:
3130 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3131 "Cleaning up connection to `%s' after sending DISCONNECT\n",
3132 GNUNET_i2s (&n->id));
3135 case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
3136 /* how did we get here!? */
3140 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3141 "Unhandled state `%s'\n",
3142 GNUNET_TRANSPORT_ps2s (n->state));
3146 delay = GNUNET_TIME_absolute_get_remaining (n->timeout);
3147 if ( (GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT == n->state) ||
3148 (GNUNET_TRANSPORT_PS_CONNECTED == n->state) )
3150 /* if we are *now* in one of the two states, we're sending
3151 keep alive messages, so we need to consider the keepalive
3152 delay, not just the connection timeout */
3153 delay = GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining (n->keep_alive_time),
3156 if (NULL == n->task)
3157 n->task = GNUNET_SCHEDULER_add_delayed (delay,
3164 * Send a ACK message to the neighbour to confirm that we
3167 * @param n neighbour to send the ACK to
3170 send_session_ack_message (struct NeighbourMapEntry *n)
3172 struct GNUNET_MessageHeader msg;
3174 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3175 "Sending ACK message to peer `%s'\n",
3176 GNUNET_i2s (&n->id));
3178 msg.size = htons (sizeof (struct GNUNET_MessageHeader));
3179 msg.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK);
3180 (void) send_with_session (n,
3182 sizeof (struct GNUNET_MessageHeader),
3184 GNUNET_TIME_UNIT_FOREVER_REL,
3191 * We received a 'SESSION_SYN_ACK' message from the other peer.
3192 * Consider switching to it.
3194 * @param message possibly a `struct SessionConnectMessage` (check format)
3195 * @param peer identity of the peer to switch the address for
3196 * @param address address of the other peer, NULL if other peer
3198 * @param session session to use (or NULL)
3199 * @return #GNUNET_OK if the message was fine, #GNUNET_SYSERR on serious error
3202 GST_neighbours_handle_session_syn_ack (const struct GNUNET_MessageHeader *message,
3203 const struct GNUNET_HELLO_Address *address,
3204 struct Session *session)
3206 const struct TransportSynMessage *scm;
3207 struct GNUNET_TIME_Absolute ts;
3208 struct NeighbourMapEntry *n;
3210 if (ntohs (message->size) != sizeof (struct TransportSynMessage))
3212 GNUNET_break_op (0);
3213 return GNUNET_SYSERR;
3215 GNUNET_STATISTICS_update (GST_stats,
3217 ("# SYN_ACK messages received"),
3219 scm = (const struct TransportSynMessage *) message;
3220 GNUNET_break_op (ntohl (scm->reserved) == 0);
3221 if (NULL == (n = lookup_neighbour (&address->peer)))
3223 GNUNET_STATISTICS_update (GST_stats,
3225 ("# unexpected SYN_ACK messages (no peer)"),
3227 return GNUNET_SYSERR;
3229 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3230 "Received SYN_ACK message from peer `%s' in state %s/%s\n",
3231 GNUNET_i2s (&address->peer),
3232 GNUNET_TRANSPORT_ps2s (n->state),
3233 print_ack_state (n->ack_state));
3234 ts = GNUNET_TIME_absolute_ntoh (scm->timestamp);
3237 case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
3240 return GNUNET_SYSERR;
3241 case GNUNET_TRANSPORT_PS_INIT_ATS:
3242 GNUNET_STATISTICS_update (GST_stats,
3243 gettext_noop ("# unexpected SYN_ACK messages (not ready)"),
3247 case GNUNET_TRANSPORT_PS_SYN_SENT:
3248 if (ts.abs_value_us != n->primary_address.connect_timestamp.abs_value_us)
3250 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3251 "SYN_ACK ignored as the timestamp does not match our SYN request\n");
3254 set_state_and_timeout (n,
3255 GNUNET_TRANSPORT_PS_CONNECTED,
3256 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT));
3257 set_primary_address (n,
3258 n->primary_address.address,
3259 n->primary_address.session,
3260 n->primary_address.bandwidth_in,
3261 n->primary_address.bandwidth_out,
3263 send_session_ack_message (n);
3265 case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
3266 case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
3267 GNUNET_STATISTICS_update (GST_stats,
3268 gettext_noop ("# unexpected SYN_ACK messages (not ready)"),
3272 case GNUNET_TRANSPORT_PS_CONNECTED:
3273 /* duplicate SYN_ACK, let's answer by duplicate ACK just in case */
3274 send_session_ack_message (n);
3276 case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
3277 /* we didn't expect any SYN_ACK, as we are waiting for ATS
3278 to give us a new address... */
3279 GNUNET_STATISTICS_update (GST_stats,
3280 gettext_noop ("# unexpected SYN_ACK messages (waiting on ATS)"),
3284 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
3285 /* Reconnecting with new address address worked; go back to connected! */
3286 set_state_and_timeout (n,
3287 GNUNET_TRANSPORT_PS_CONNECTED,
3288 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT));
3289 send_session_ack_message (n);
3291 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
3292 /* new address worked; adopt it and go back to connected! */
3293 set_state_and_timeout (n,
3294 GNUNET_TRANSPORT_PS_CONNECTED,
3295 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT));
3296 GNUNET_break (GNUNET_NO == n->alternative_address.ats_active);
3298 /* Set primary addresses */
3299 set_primary_address (n,
3300 n->alternative_address.address,
3301 n->alternative_address.session,
3302 n->alternative_address.bandwidth_in,
3303 n->alternative_address.bandwidth_out,
3305 GNUNET_STATISTICS_update (GST_stats,
3306 gettext_noop ("# Successful attempts to switch addresses"),
3310 GNUNET_HELLO_address_free (n->alternative_address.address);
3311 memset (&n->alternative_address,
3313 sizeof (n->alternative_address));
3314 send_session_ack_message (n);
3316 case GNUNET_TRANSPORT_PS_DISCONNECT:
3317 GNUNET_STATISTICS_update (GST_stats,
3319 ("# unexpected SYN_ACK messages (disconnecting)"),
3321 return GNUNET_SYSERR;
3322 case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
3326 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3327 "Unhandled state `%s'\n",
3328 GNUNET_TRANSPORT_ps2s (n->state));
3330 return GNUNET_SYSERR;
3337 * A session was terminated. Take note; if needed, try to get
3338 * an alternative address from ATS.
3340 * @param peer identity of the peer where the session died
3341 * @param session session that is gone
3342 * @return #GNUNET_YES if this was a session used, #GNUNET_NO if
3343 * this session was not in use
3346 GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer,
3347 struct Session *session)
3349 struct NeighbourMapEntry *n;
3350 struct BlackListCheckContext *bcc;
3351 struct BlackListCheckContext *bcc_next;
3353 /* make sure to cancel all ongoing blacklist checks involving 'session' */
3355 while (NULL != (bcc = bcc_next))
3357 bcc_next = bcc->next;
3358 if (bcc->na.session == session)
3360 if (NULL != bcc->bc)
3361 GST_blacklist_test_cancel (bcc->bc);
3362 GNUNET_HELLO_address_free (bcc->na.address);
3363 GNUNET_CONTAINER_DLL_remove (bc_head,
3369 if (NULL == (n = lookup_neighbour (peer)))
3370 return GNUNET_NO; /* can't affect us */
3371 if (session != n->primary_address.session)
3373 /* Free alternative address */
3374 if (session == n->alternative_address.session)
3376 if (GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT == n->state)
3377 set_state_and_timeout (n,
3378 GNUNET_TRANSPORT_PS_CONNECTED,
3380 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3381 "Session died, cleaning up alternative address\n");
3382 free_address (&n->alternative_address);
3384 return GNUNET_NO; /* doesn't affect us further */
3387 n->expect_latency_response = GNUNET_NO;
3388 /* The session for neighbour's primary address died */
3391 case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
3395 case GNUNET_TRANSPORT_PS_INIT_ATS:
3399 case GNUNET_TRANSPORT_PS_SYN_SENT:
3400 /* The session used to send the SYN terminated:
3401 * this implies a connect error*/
3402 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3403 "Failed to send SYN in %s with `%s' %p: session terminated\n",
3405 GST_plugins_a2s (n->primary_address.address),
3406 n->primary_address.session,
3409 /* Destroy the address since it cannot be used */
3410 unset_primary_address (n);
3411 set_state_and_timeout (n,
3412 GNUNET_TRANSPORT_PS_INIT_ATS,
3413 GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT));
3415 case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
3416 case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
3417 /* error on inbound session; free neighbour entirely */
3420 case GNUNET_TRANSPORT_PS_CONNECTED:
3421 /* Our primary connection died, try a fast reconnect */
3422 unset_primary_address (n);
3423 set_state_and_timeout (n,
3424 GNUNET_TRANSPORT_PS_RECONNECT_ATS,
3425 GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT));
3427 case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
3428 /* we don't have an address, how can it go down? */
3431 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
3432 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3433 "Failed to send SYN in %s with `%s' %p: session terminated\n",
3435 GST_plugins_a2s (n->primary_address.address),
3436 n->primary_address.session,
3438 /* Destroy the address since it cannot be used */
3439 unset_primary_address (n);
3440 set_state_and_timeout (n,
3441 GNUNET_TRANSPORT_PS_RECONNECT_ATS,
3442 GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT));
3444 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
3445 /* primary went down while we were waiting for SYN_ACK on secondary;
3446 secondary as primary */
3448 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3449 "Connection `%s' %p to peer `%s' was terminated while switching, "
3450 "switching to alternative address `%s' %p\n",
3451 GST_plugins_a2s (n->primary_address.address),
3452 n->primary_address.session,
3454 GST_plugins_a2s (n->alternative_address.address),
3455 n->alternative_address.session);
3457 /* Destroy the inbound address since it cannot be used */
3458 free_address (&n->primary_address);
3459 n->primary_address = n->alternative_address;
3460 memset (&n->alternative_address,
3462 sizeof (struct NeighbourAddress));
3463 set_state_and_timeout (n,
3464 GNUNET_TRANSPORT_PS_RECONNECT_SENT,
3465 GNUNET_TIME_relative_to_absolute (FAST_RECONNECT_TIMEOUT));
3467 case GNUNET_TRANSPORT_PS_DISCONNECT:
3468 unset_primary_address (n);
3470 case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
3471 /* neighbour was freed and plugins told to terminate session */
3474 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3475 "Unhandled state `%s'\n",
3476 GNUNET_TRANSPORT_ps2s (n->state));
3480 if (NULL != n->task)
3481 GNUNET_SCHEDULER_cancel (n->task);
3482 n->task = GNUNET_SCHEDULER_add_now (&master_task, n);
3488 * We received a 'ACK' message from the other peer.
3489 * If we sent a 'SYN_ACK' last, this means we are now
3490 * connected. Otherwise, do nothing.
3492 * @param message possibly a 'struct SessionConnectMessage' (check format)
3493 * @param address address of the other peer
3494 * @param session session to use (or NULL)
3495 * @return #GNUNET_OK if the message was fine, #GNUNET_SYSERR on serious error
3498 GST_neighbours_handle_session_ack (const struct GNUNET_MessageHeader *message,
3499 const struct GNUNET_HELLO_Address *address,
3500 struct Session *session)
3502 struct NeighbourMapEntry *n;
3504 if (ntohs (message->size) != sizeof (struct GNUNET_MessageHeader))
3506 GNUNET_break_op (0);
3507 return GNUNET_SYSERR;
3509 GNUNET_STATISTICS_update (GST_stats,
3511 ("# ACK messages received"),
3513 if (NULL == (n = lookup_neighbour (&address->peer)))
3515 GNUNET_break_op (0);
3516 return GNUNET_SYSERR;
3518 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3519 "Received ACK for peer `%s' in state %s/%s\n",
3520 GNUNET_i2s (&address->peer),
3521 GNUNET_TRANSPORT_ps2s (n->state),
3522 print_ack_state (n->ack_state));
3524 /* Check if we are in a plausible state for having sent
3525 a SYN_ACK. If not, return, otherwise break.
3527 The remote peers sends a ACK as a response for a SYN_ACK
3531 - If a remote peer has sent a SYN, we responded with a SYN_ACK and
3532 now wait for the ACK to finally be connected
3533 - If we sent a SYN_ACK to this peer before */
3535 if ( (GNUNET_TRANSPORT_PS_SYN_RECV_ACK != n->state) &&
3536 (ACK_SEND_ACK != n->ack_state))
3538 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3539 "Received unexpected ACK message from peer `%s' in state %s/%s\n",
3540 GNUNET_i2s (&address->peer),
3541 GNUNET_TRANSPORT_ps2s (n->state),
3542 print_ack_state (n->ack_state));
3544 GNUNET_STATISTICS_update (GST_stats,
3545 gettext_noop ("# unexpected ACK messages"), 1,
3549 if (GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT == n->state)
3551 /* We tried to switch addresses while being connect. We explicitly wait
3552 * for a SYN_ACK before going to GNUNET_TRANSPORT_PS_CONNECTED,
3553 * so we do not want to set the address as in use! */
3556 set_state_and_timeout (n,
3557 GNUNET_TRANSPORT_PS_CONNECTED,
3558 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT));
3560 /* Set primary address to used */
3561 set_primary_address (n,
3562 n->primary_address.address,
3563 n->primary_address.session,
3564 n->primary_address.bandwidth_in,
3565 n->primary_address.bandwidth_out,
3572 * Test if we're connected to the given peer.
3574 * @param target peer to test
3575 * @return #GNUNET_YES if we are connected, #GNUNET_NO if not
3578 GST_neighbours_test_connected (const struct GNUNET_PeerIdentity *target)
3580 return test_connected (lookup_neighbour (target));
3585 * Change the incoming quota for the given peer.
3587 * @param neighbour identity of peer to change qutoa for
3588 * @param quota new quota
3591 GST_neighbours_set_incoming_quota (const struct GNUNET_PeerIdentity *neighbour,
3592 struct GNUNET_BANDWIDTH_Value32NBO quota)
3594 struct NeighbourMapEntry *n;
3596 if (NULL == (n = lookup_neighbour (neighbour)))
3598 GNUNET_STATISTICS_update (GST_stats,
3600 ("# SET QUOTA messages ignored (no such peer)"),
3604 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3605 "Setting inbound quota of %u Bps for peer `%s' to all clients\n",
3606 ntohl (quota.value__), GNUNET_i2s (&n->id));
3607 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker, quota);
3608 if (0 != ntohl (quota.value__))
3610 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3611 "Disconnecting peer `%4s' due to SET_QUOTA\n",
3612 GNUNET_i2s (&n->id));
3613 if (GNUNET_YES == test_connected (n))
3614 GNUNET_STATISTICS_update (GST_stats,
3615 gettext_noop ("# disconnects due to quota of 0"),
3617 disconnect_neighbour (n);
3622 * Task to asynchronously run #free_neighbour().
3624 * @param cls the `struct NeighbourMapEntry` to free
3628 delayed_disconnect (void *cls,
3629 const struct GNUNET_SCHEDULER_TaskContext* tc)
3631 struct NeighbourMapEntry *n = cls;
3633 n->delayed_disconnect_task = NULL;
3634 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3635 "Disconnecting by request from peer %s\n",
3636 GNUNET_i2s (&n->id));
3642 * We received a disconnect message from the given peer,
3643 * validate and process.
3645 * @param peer sender of the message
3646 * @param msg the disconnect message
3649 GST_neighbours_handle_disconnect_message (const struct GNUNET_PeerIdentity *peer,
3650 const struct GNUNET_MessageHeader *msg)
3652 struct NeighbourMapEntry *n;
3653 const struct SessionDisconnectMessage *sdm;
3655 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3656 "Received DISCONNECT message from peer `%s'\n",
3658 if (ntohs (msg->size) != sizeof (struct SessionDisconnectMessage))
3660 GNUNET_break_op (0);
3661 GNUNET_STATISTICS_update (GST_stats,
3663 ("# disconnect messages ignored (malformed)"), 1,
3667 GNUNET_STATISTICS_update (GST_stats,
3669 ("# DISCONNECT messages received"),
3671 sdm = (const struct SessionDisconnectMessage *) msg;
3672 if (NULL == (n = lookup_neighbour (peer)))
3677 if (GNUNET_TIME_absolute_ntoh (sdm->timestamp).abs_value_us <= n->connect_ack_timestamp.abs_value_us)
3679 GNUNET_STATISTICS_update (GST_stats,
3680 gettext_noop ("# disconnect messages ignored (timestamp)"),
3685 if (0 != memcmp (peer,
3687 sizeof (struct GNUNET_PeerIdentity)))
3689 GNUNET_break_op (0);
3692 if (ntohl (sdm->purpose.size) !=
3693 sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
3694 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey) +
3695 sizeof (struct GNUNET_TIME_AbsoluteNBO))
3697 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3698 "DISCONNECT message from peer `%s' has invalid size\n",
3700 GNUNET_break_op (0);
3704 GNUNET_CRYPTO_eddsa_verify (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT,
3709 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3710 "DISCONNECT message from peer `%s' cannot be verified \n",
3712 GNUNET_break_op (0);
3715 n->delayed_disconnect_task = GNUNET_SCHEDULER_add_now (&delayed_disconnect, n);
3720 * Closure for the #neighbours_iterate() function.
3722 struct IteratorContext
3725 * Function to call on each connected neighbour.
3727 GST_NeighbourIterator cb;
3730 * Closure for @e cb.
3737 * Call the callback from the closure for each neighbour.
3739 * @param cls the `struct IteratorContext`
3740 * @param key the hash of the public key of the neighbour
3741 * @param value the `struct NeighbourMapEntry`
3742 * @return #GNUNET_OK (continue to iterate)
3745 neighbours_iterate (void *cls,
3746 const struct GNUNET_PeerIdentity *key,
3749 struct IteratorContext *ic = cls;
3750 struct NeighbourMapEntry *n = value;
3751 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
3752 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
3754 if (NULL != n->primary_address.address)
3756 bandwidth_in = n->primary_address.bandwidth_in;
3757 bandwidth_out = n->primary_address.bandwidth_out;
3761 bandwidth_in = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
3762 bandwidth_out = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
3766 n->primary_address.address,
3769 bandwidth_in, bandwidth_out);
3775 * Iterate over all connected neighbours.
3777 * @param cb function to call
3778 * @param cb_cls closure for cb
3781 GST_neighbours_iterate (GST_NeighbourIterator cb, void *cb_cls)
3783 struct IteratorContext ic;
3785 if (NULL == neighbours)
3786 return; /* can happen during shutdown */
3789 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &neighbours_iterate, &ic);
3794 * If we have an active connection to the given target, it must be shutdown.
3796 * @param target peer to disconnect from
3799 GST_neighbours_force_disconnect (const struct GNUNET_PeerIdentity *target)
3801 struct NeighbourMapEntry *n;
3803 if (NULL == (n = lookup_neighbour (target)))
3804 return; /* not active */
3805 if (GNUNET_YES == test_connected (n))
3806 GNUNET_STATISTICS_update (GST_stats,
3807 gettext_noop ("# disconnected from peer upon explicit request"),
3810 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3811 "Forced disconnect from peer %s\n",
3812 GNUNET_i2s (target));
3813 disconnect_neighbour (n);
3818 * Obtain current address information for the given neighbour.
3821 * @return address currently used
3823 struct GNUNET_HELLO_Address *
3824 GST_neighbour_get_current_address (const struct GNUNET_PeerIdentity *peer)
3826 struct NeighbourMapEntry *n;
3828 n = lookup_neighbour (peer);
3831 return n->primary_address.address;
3836 * Initialize the neighbours subsystem.
3838 * @param max_fds maximum number of fds to use
3841 GST_neighbours_start (unsigned int max_fds)
3843 neighbours = GNUNET_CONTAINER_multipeermap_create (NEIGHBOUR_TABLE_SIZE,
3845 util_transmission_tk = GNUNET_SCHEDULER_add_delayed (UTIL_TRANSMISSION_INTERVAL,
3846 &utilization_transmission,
3852 * Disconnect from the given neighbour.
3855 * @param key hash of neighbour's public key (not used)
3856 * @param value the 'struct NeighbourMapEntry' of the neighbour
3857 * @return #GNUNET_OK (continue to iterate)
3860 disconnect_all_neighbours (void *cls,
3861 const struct GNUNET_PeerIdentity *key,
3864 struct NeighbourMapEntry *n = value;
3866 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3867 "Disconnecting peer `%4s' during shutdown\n",
3868 GNUNET_i2s (&n->id));
3875 * Cleanup the neighbours subsystem.
3878 GST_neighbours_stop ()
3880 struct BlacklistCheckSwitchContext *cur;
3881 struct BlacklistCheckSwitchContext *next;
3883 if (NULL == neighbours)
3885 if (NULL != util_transmission_tk)
3887 GNUNET_SCHEDULER_cancel (util_transmission_tk);
3888 util_transmission_tk = NULL;
3890 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
3891 &disconnect_all_neighbours,
3893 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
3895 next = pending_bc_head;
3896 for (cur = next; NULL != cur; cur = next)
3899 GNUNET_CONTAINER_DLL_remove (pending_bc_head,
3903 if (NULL != cur->blc)
3905 GST_blacklist_test_cancel (cur->blc);
3908 if (NULL != cur->address)
3909 GNUNET_HELLO_address_free (cur->address);
3915 /* end of file gnunet-service-transport_neighbours.c */