2 This file is part of GNUnet.
3 (C) 2010,2011 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file 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_neighbours.h"
29 #include "gnunet-service-transport_plugins.h"
30 #include "gnunet-service-transport_validation.h"
31 #include "gnunet-service-transport_clients.h"
32 #include "gnunet-service-transport.h"
33 #include "gnunet_peerinfo_service.h"
34 #include "gnunet-service-transport_blacklist.h"
35 #include "gnunet_constants.h"
36 #include "transport.h"
40 * Size of the neighbour hash map.
42 #define NEIGHBOUR_TABLE_SIZE 256
45 * How often must a peer violate bandwidth quotas before we start
46 * to simply drop its messages?
48 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
51 * How often do we send KEEPALIVE messages to each of our neighbours and measure
52 * the latency with this neighbour?
53 * (idle timeout is 5 minutes or 300 seconds, so with 30s interval we
54 * send 10 keepalives in each interval, so 10 messages would need to be
55 * lost in a row for a disconnect).
57 #define KEEPALIVE_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
60 #define ATS_RESPONSE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)
62 #define FAST_RECONNECT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
64 #define SETUP_CONNECTION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
68 * Entry in neighbours.
70 struct NeighbourMapEntry;
73 * Message a peer sends to another to indicate its
74 * preference for communicating via a particular
75 * session (and the desire to establish a real
78 struct SessionConnectMessage
81 * Header of type 'GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT'
83 struct GNUNET_MessageHeader header;
88 uint32_t reserved GNUNET_PACKED;
91 * Absolute time at the sender. Only the most recent connect
92 * message implies which session is preferred by the sender.
94 struct GNUNET_TIME_AbsoluteNBO timestamp;
99 struct SessionDisconnectMessage
102 * Header of type 'GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT'
104 struct GNUNET_MessageHeader header;
109 uint32_t reserved GNUNET_PACKED;
112 * Purpose of the signature. Extends over the timestamp.
113 * Purpose should be GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DISCONNECT.
115 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
118 * Absolute time at the sender. Only the most recent connect
119 * message implies which session is preferred by the sender.
121 struct GNUNET_TIME_AbsoluteNBO timestamp;
124 * Public key of the sender.
126 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
129 * Signature of the peer that sends us the disconnect. Only
130 * valid if the timestamp is AFTER the timestamp from the
131 * corresponding 'CONNECT' message.
133 struct GNUNET_CRYPTO_RsaSignature signature;
139 * For each neighbour we keep a list of messages
140 * that we still want to transmit to the neighbour.
146 * This is a doubly linked list.
148 struct MessageQueue *next;
151 * This is a doubly linked list.
153 struct MessageQueue *prev;
156 * Once this message is actively being transmitted, which
157 * neighbour is it associated with?
159 struct NeighbourMapEntry *n;
162 * Function to call once we're done.
164 GST_NeighbourSendContinuation cont;
172 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
173 * stuck together in memory. Allocated at the end of this struct.
175 const char *message_buf;
178 * Size of the message buf
180 size_t message_buf_size;
183 * At what time should we fail?
185 struct GNUNET_TIME_Absolute timeout;
193 * fresh peer or completely disconnected
198 * sent CONNECT message to other peer, waiting for CONNECT_ACK
203 * received CONNECT message to other peer, sending CONNECT_ACK
208 * received ACK or payload
213 * connection ended, fast reconnect
218 * Disconnect in progress
231 * Entry in neighbours.
233 struct NeighbourMapEntry
237 * Head of list of messages we would like to send to this peer;
238 * must contain at most one message per client.
240 struct MessageQueue *messages_head;
243 * Tail of list of messages we would like to send to this peer; must
244 * contain at most one message per client.
246 struct MessageQueue *messages_tail;
249 * Performance data for the peer.
251 //struct GNUNET_ATS_Information *ats;
254 * Are we currently trying to send a message? If so, which one?
256 struct MessageQueue *is_active;
259 * Active session for communicating with the peer.
261 struct Session *session;
264 * Address we currently use.
266 struct GNUNET_HELLO_Address *address;
269 * Identity of this neighbour.
271 struct GNUNET_PeerIdentity id;
274 * ID of task scheduled to run when this peer is about to
275 * time out (will free resources associated with the peer).
277 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
280 * ID of task scheduled to send keepalives.
282 GNUNET_SCHEDULER_TaskIdentifier keepalive_task;
285 * ID of task scheduled to run when we should try transmitting
286 * the head of the message queue.
288 GNUNET_SCHEDULER_TaskIdentifier transmission_task;
291 * Tracker for inbound bandwidth.
293 struct GNUNET_BANDWIDTH_Tracker in_tracker;
296 * Inbound bandwidth from ATS, activated when connection is up
298 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
301 * Inbound bandwidth from ATS, activated when connection is up
303 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
306 * Timestamp of the 'SESSION_CONNECT' message we got from the other peer
308 struct GNUNET_TIME_Absolute connect_ts;
311 * When did we sent the last keep-alive message?
313 struct GNUNET_TIME_Absolute keep_alive_sent;
316 * Latest calculated latency value
318 struct GNUNET_TIME_Relative latency;
322 * We asked ATS for a new address for this peer
324 GNUNET_SCHEDULER_TaskIdentifier ats_suggest;
327 * Task the resets the peer state after due to an pending
328 * unsuccessful connection setup
330 GNUNET_SCHEDULER_TaskIdentifier state_reset;
333 * How often has the other peer (recently) violated the inbound
334 * traffic limit? Incremented by 10 per violation, decremented by 1
335 * per non-violation (for each time interval).
337 unsigned int quota_violation_count;
341 * The current state of the peer
342 * Element of enum State
347 * Did we sent an KEEP_ALIVE message and are we expecting a response?
349 int expect_latency_response;
355 * All known neighbours and their HELLOs.
357 static struct GNUNET_CONTAINER_MultiHashMap *neighbours;
360 * Closure for connect_notify_cb and disconnect_notify_cb
362 static void *callback_cls;
365 * Function to call when we connected to a neighbour.
367 static GNUNET_TRANSPORT_NotifyConnect connect_notify_cb;
370 * Function to call when we disconnected from a neighbour.
372 static GNUNET_TRANSPORT_NotifyDisconnect disconnect_notify_cb;
375 * counter for connected neighbours
377 static int neighbours_connected;
380 * Lookup a neighbour entry in the neighbours hash map.
382 * @param pid identity of the peer to look up
383 * @return the entry, NULL if there is no existing record
385 static struct NeighbourMapEntry *
386 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
388 return GNUNET_CONTAINER_multihashmap_get (neighbours, &pid->hashPubKey);
391 #define change_state(n, state, ...) change (n, state, __LINE__)
394 is_connecting (struct NeighbourMapEntry *n)
396 if ((n->state > S_NOT_CONNECTED) && (n->state < S_CONNECTED))
402 is_connected (struct NeighbourMapEntry *n)
404 if (n->state == S_CONNECTED)
410 is_disconnecting (struct NeighbourMapEntry *n)
412 if (n->state == S_DISCONNECT)
418 print_state (int state)
423 return "S_CONNECTED";
426 return "S_CONNECT_RECV";
429 return "S_CONNECT_SENT";
432 return "S_DISCONNECT";
434 case S_NOT_CONNECTED:
435 return "S_NOT_CONNECTED";
437 case S_FAST_RECONNECT:
438 return "S_FAST_RECONNECT";
448 change (struct NeighbourMapEntry *n, int state, int line);
451 ats_suggest_cancel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
455 reset_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
457 struct NeighbourMapEntry *n = cls;
459 n->state_reset = GNUNET_SCHEDULER_NO_TASK;
460 if (n->state == S_CONNECTED)
464 GNUNET_STATISTICS_update (GST_stats,
466 ("# failed connection attempts due to timeout"), 1,
470 /* resetting state */
471 n->state = S_NOT_CONNECTED;
473 /* destroying address */
474 GNUNET_assert (strlen(n->address->transport_name) > 0);
475 GNUNET_ATS_address_destroyed (GST_ats, n->address, n->session);
477 /* request new address */
478 if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
479 GNUNET_SCHEDULER_cancel (n->ats_suggest);
481 GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel,
483 GNUNET_ATS_suggest_address (GST_ats, &n->id);
487 change (struct NeighbourMapEntry *n, int state, int line)
489 /* allowed transitions */
490 int allowed = GNUNET_NO;
494 case S_NOT_CONNECTED:
495 if ((state == S_CONNECT_RECV) || (state == S_CONNECT_SENT) ||
496 (state == S_DISCONNECT))
497 allowed = GNUNET_YES;
500 allowed = GNUNET_YES;
503 allowed = GNUNET_YES;
506 if ((state == S_DISCONNECT) || (state == S_FAST_RECONNECT))
507 allowed = GNUNET_YES;
511 case S_FAST_RECONNECT:
512 if ((state == S_CONNECTED) || (state == S_DISCONNECT))
513 allowed = GNUNET_YES;
519 if (allowed == GNUNET_NO)
521 char *old = GNUNET_strdup (print_state (n->state));
522 char *new = GNUNET_strdup (print_state (state));
523 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
524 "Illegal state transition from `%s' to `%s' in line %u \n", old,
529 return GNUNET_SYSERR;
534 char *old = GNUNET_strdup (print_state (n->state));
535 char *new = GNUNET_strdup (print_state (state));
536 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
537 "State for neighbour `%s' %X changed from `%s' to `%s' in line %u\n",
538 GNUNET_i2s (&n->id), n, old, new, line);
547 case S_FAST_RECONNECT:
550 if (n->state_reset != GNUNET_SCHEDULER_NO_TASK)
551 GNUNET_SCHEDULER_cancel (n->state_reset);
553 GNUNET_SCHEDULER_add_delayed (SETUP_CONNECTION_TIMEOUT, &reset_task,
557 case S_NOT_CONNECTED:
559 if (GNUNET_SCHEDULER_NO_TASK != n->state_reset)
562 char *old = GNUNET_strdup (print_state (n->state));
563 char *new = GNUNET_strdup (print_state (state));
564 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
565 "Removed reset task for peer `%s' %s failed in state transition `%s' -> `%s' \n",
566 GNUNET_i2s (&n->id), GST_plugins_a2s (n->address),
571 GNUNET_assert (n->state_reset != GNUNET_SCHEDULER_NO_TASK);
572 GNUNET_SCHEDULER_cancel (n->state_reset);
573 n->state_reset = GNUNET_SCHEDULER_NO_TASK;
587 send_with_plugin (const struct GNUNET_PeerIdentity *target, const char *msgbuf,
588 size_t msgbuf_size, uint32_t priority,
589 struct GNUNET_TIME_Relative timeout, struct Session *session,
590 const struct GNUNET_HELLO_Address *address,
591 int force_address, GNUNET_TRANSPORT_TransmitContinuation cont,
594 struct GNUNET_TRANSPORT_PluginFunctions *papi;
595 size_t ret = GNUNET_SYSERR;
597 /* FIXME : ats returns an address with all values 0 */
601 cont (cont_cls, target, GNUNET_SYSERR);
602 return GNUNET_SYSERR;
605 if ((session == NULL) && (address->address_length == 0))
608 cont (cont_cls, target, GNUNET_SYSERR);
609 return GNUNET_SYSERR;
612 papi = GST_plugins_find (address->transport_name);
616 cont (cont_cls, target, GNUNET_SYSERR);
617 return GNUNET_SYSERR;
621 papi->send (papi->cls, target, msgbuf, msgbuf_size, 0, timeout, session,
623 address->address_length, GNUNET_YES, cont, cont_cls);
628 cont (cont_cls, target, GNUNET_SYSERR);
634 * Task invoked to start a transmission to another peer.
636 * @param cls the 'struct NeighbourMapEntry'
637 * @param tc scheduler context
640 transmission_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
644 * We're done with our transmission attempt, continue processing.
646 * @param cls the 'struct MessageQueue' of the message
647 * @param receiver intended receiver
648 * @param success whether it worked or not
651 transmit_send_continuation (void *cls,
652 const struct GNUNET_PeerIdentity *receiver,
655 struct MessageQueue *mq;
656 struct NeighbourMapEntry *n;
662 GNUNET_assert (n->is_active == mq);
664 if (success == GNUNET_YES)
666 GNUNET_assert (n->transmission_task == GNUNET_SCHEDULER_NO_TASK);
667 n->transmission_task = GNUNET_SCHEDULER_add_now (&transmission_task, n);
671 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message of type %u was %s\n",
672 ntohs (((struct GNUNET_MessageHeader *) mq->message_buf)->type),
673 (success == GNUNET_OK) ? "successful" : "FAILED");
675 if (NULL != mq->cont)
676 mq->cont (mq->cont_cls, success);
682 * Check the ready list for the given neighbour and if a plugin is
683 * ready for transmission (and if we have a message), do so!
685 * @param n target peer for which to transmit
688 try_transmission_to_peer (struct NeighbourMapEntry *n)
690 struct MessageQueue *mq;
691 struct GNUNET_TIME_Relative timeout;
694 if (n->is_active != NULL)
697 return; /* transmission already pending */
699 if (n->transmission_task != GNUNET_SCHEDULER_NO_TASK)
702 return; /* currently waiting for bandwidth */
704 while (NULL != (mq = n->messages_head))
706 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
707 if (timeout.rel_value > 0)
709 GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
712 transmit_send_continuation (mq, &n->id, GNUNET_SYSERR); /* timeout */
715 return; /* no more messages */
717 if (n->address == NULL)
719 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
720 "No address for peer `%s'\n",
721 GNUNET_i2s (&n->id));
722 transmit_send_continuation (mq, &n->id, GNUNET_SYSERR);
723 GNUNET_assert (n->transmission_task == GNUNET_SCHEDULER_NO_TASK);
724 n->transmission_task = GNUNET_SCHEDULER_add_now (&transmission_task, n);
728 if (GST_plugins_find (n->address->transport_name) == NULL)
733 GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
737 if ((n->address->address_length == 0) && (n->session == NULL))
739 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
740 "No address for peer `%s'\n",
741 GNUNET_i2s (&n->id));
742 transmit_send_continuation (mq, &n->id, GNUNET_SYSERR);
743 GNUNET_assert (n->transmission_task == GNUNET_SCHEDULER_NO_TASK);
744 n->transmission_task = GNUNET_SCHEDULER_add_now (&transmission_task, n);
749 send_with_plugin (&n->id, mq->message_buf, mq->message_buf_size, 0,
750 timeout, n->session, n->address,
751 GNUNET_YES, &transmit_send_continuation,
755 /* failure, but 'send' would not call continuation in this case,
756 * so we need to do it here! */
757 transmit_send_continuation (mq, &n->id, GNUNET_SYSERR);
764 * Task invoked to start a transmission to another peer.
766 * @param cls the 'struct NeighbourMapEntry'
767 * @param tc scheduler context
770 transmission_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
772 struct NeighbourMapEntry *n = cls;
774 GNUNET_assert (NULL != lookup_neighbour (&n->id));
775 n->transmission_task = GNUNET_SCHEDULER_NO_TASK;
776 try_transmission_to_peer (n);
781 * Initialize the neighbours subsystem.
783 * @param cls closure for callbacks
784 * @param connect_cb function to call if we connect to a peer
785 * @param disconnect_cb function to call if we disconnect from a peer
788 GST_neighbours_start (void *cls, GNUNET_TRANSPORT_NotifyConnect connect_cb,
789 GNUNET_TRANSPORT_NotifyDisconnect disconnect_cb)
792 connect_notify_cb = connect_cb;
793 disconnect_notify_cb = disconnect_cb;
794 neighbours = GNUNET_CONTAINER_multihashmap_create (NEIGHBOUR_TABLE_SIZE);
799 send_disconnect_cont (void *cls, const struct GNUNET_PeerIdentity *target,
803 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
804 "Sending DISCONNECT message to peer `%4s': %i\n",
805 GNUNET_i2s (target), result);
811 send_disconnect (const struct GNUNET_PeerIdentity *target,
812 const struct GNUNET_HELLO_Address *address,
813 struct Session *session)
816 struct SessionDisconnectMessage disconnect_msg;
819 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
820 "Sending DISCONNECT message to peer `%4s'\n",
821 GNUNET_i2s (target));
824 disconnect_msg.header.size = htons (sizeof (struct SessionDisconnectMessage));
825 disconnect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
826 disconnect_msg.reserved = htonl (0);
827 disconnect_msg.purpose.size =
828 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
829 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) +
830 sizeof (struct GNUNET_TIME_AbsoluteNBO));
831 disconnect_msg.purpose.purpose =
832 htonl (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT);
833 disconnect_msg.timestamp =
834 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
835 disconnect_msg.public_key = GST_my_public_key;
836 GNUNET_assert (GNUNET_OK ==
837 GNUNET_CRYPTO_rsa_sign (GST_my_private_key,
838 &disconnect_msg.purpose,
839 &disconnect_msg.signature));
842 send_with_plugin (target, (const char *) &disconnect_msg,
843 sizeof (disconnect_msg), UINT32_MAX,
844 GNUNET_TIME_UNIT_FOREVER_REL, session, address,
846 &send_disconnect_cont, NULL);
848 if (ret == GNUNET_SYSERR)
849 return GNUNET_SYSERR;
851 GNUNET_STATISTICS_update (GST_stats,
853 ("# peers disconnected due to external request"), 1,
860 * Disconnect from the given neighbour, clean up the record.
862 * @param n neighbour to disconnect from
865 disconnect_neighbour (struct NeighbourMapEntry *n)
867 struct MessageQueue *mq;
870 previous_state = n->state;
872 if (is_disconnecting (n))
876 /* send DISCONNECT MESSAGE */
877 if ((previous_state == S_CONNECTED) || is_connecting (n))
880 send_disconnect (&n->id, n->address,
882 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent DISCONNECT_MSG to `%s'\n",
883 GNUNET_i2s (&n->id));
885 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
886 "Could not send DISCONNECT_MSG to `%s'\n",
887 GNUNET_i2s (&n->id));
890 change_state (n, S_DISCONNECT);
892 if (previous_state == S_CONNECTED)
894 GNUNET_assert (NULL != n->address);
895 if (n->address_state == USED)
897 GST_validation_set_address_use (&n->id,
902 GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_NO);
903 n->address_state = UNUSED;
907 if (n->address != NULL)
909 struct GNUNET_TRANSPORT_PluginFunctions *papi;
910 papi = GST_plugins_find (n->address->transport_name);
912 papi->disconnect (papi->cls, &n->id);
914 while (NULL != (mq = n->messages_head))
916 GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
917 if (NULL != mq->cont)
918 mq->cont (mq->cont_cls, GNUNET_SYSERR);
921 if (NULL != n->is_active)
923 n->is_active->n = NULL;
927 switch (previous_state) {
929 // GNUNET_assert (neighbours_connected > 0);
930 neighbours_connected--;
931 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != n->keepalive_task);
932 GNUNET_SCHEDULER_cancel (n->keepalive_task);
933 n->keepalive_task = GNUNET_SCHEDULER_NO_TASK;
934 GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), -1,
936 disconnect_notify_cb (callback_cls, &n->id);
938 case S_FAST_RECONNECT:
939 GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), -1,
941 GNUNET_STATISTICS_update (GST_stats,
943 ("# fast reconnects failed"),
945 disconnect_notify_cb (callback_cls, &n->id);
950 GNUNET_ATS_suggest_address_cancel (GST_ats, &n->id);
952 GNUNET_assert (GNUNET_YES ==
953 GNUNET_CONTAINER_multihashmap_remove (neighbours,
954 &n->id.hashPubKey, n));
955 if (GNUNET_SCHEDULER_NO_TASK != n->ats_suggest)
957 GNUNET_SCHEDULER_cancel (n->ats_suggest);
958 n->ats_suggest = GNUNET_SCHEDULER_NO_TASK;
960 if (GNUNET_SCHEDULER_NO_TASK != n->timeout_task)
962 GNUNET_SCHEDULER_cancel (n->timeout_task);
963 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
965 if (GNUNET_SCHEDULER_NO_TASK != n->transmission_task)
967 GNUNET_SCHEDULER_cancel (n->transmission_task);
968 n->transmission_task = GNUNET_SCHEDULER_NO_TASK;
970 if (NULL != n->address)
972 GNUNET_HELLO_address_free (n->address);
976 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting peer `%4s', %X\n",
977 GNUNET_i2s (&n->id), n);
983 * Peer has been idle for too long. Disconnect.
985 * @param cls the 'struct NeighbourMapEntry' of the neighbour that went idle
986 * @param tc scheduler context
989 neighbour_timeout_task (void *cls,
990 const struct GNUNET_SCHEDULER_TaskContext *tc)
992 struct NeighbourMapEntry *n = cls;
994 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
996 GNUNET_STATISTICS_update (GST_stats,
998 ("# peers disconnected due to timeout"), 1,
1000 disconnect_neighbour (n);
1005 * Send another keepalive message.
1007 * @param cls the 'struct NeighbourMapEntry' of the neighbour that went idle
1008 * @param tc scheduler context
1011 neighbour_keepalive_task (void *cls,
1012 const struct GNUNET_SCHEDULER_TaskContext *tc)
1014 struct NeighbourMapEntry *n = cls;
1015 struct GNUNET_MessageHeader m;
1019 GNUNET_SCHEDULER_add_delayed (KEEPALIVE_FREQUENCY,
1020 &neighbour_keepalive_task, n);
1022 GNUNET_assert (S_CONNECTED == n->state);
1023 GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# keepalives sent"), 1,
1025 m.size = htons (sizeof (struct GNUNET_MessageHeader));
1026 m.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE);
1029 ret = send_with_plugin (&n->id, (const void *) &m, sizeof (m),
1030 UINT32_MAX /* priority */ ,
1031 GNUNET_TIME_UNIT_FOREVER_REL, n->session, n->address,
1032 GNUNET_YES, NULL, NULL);
1034 n->expect_latency_response = GNUNET_NO;
1035 n->keep_alive_sent = GNUNET_TIME_absolute_get_zero();
1036 if (ret != GNUNET_SYSERR)
1038 n->expect_latency_response = GNUNET_YES;
1039 n->keep_alive_sent = GNUNET_TIME_absolute_get();
1046 * Disconnect from the given neighbour.
1049 * @param key hash of neighbour's public key (not used)
1050 * @param value the 'struct NeighbourMapEntry' of the neighbour
1053 disconnect_all_neighbours (void *cls, const GNUNET_HashCode * key, void *value)
1055 struct NeighbourMapEntry *n = value;
1058 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s', %s\n",
1059 GNUNET_i2s (&n->id), "SHUTDOWN_TASK");
1061 if (S_CONNECTED == n->state)
1062 GNUNET_STATISTICS_update (GST_stats,
1064 ("# peers disconnected due to global disconnect"),
1066 disconnect_neighbour (n);
1072 ats_suggest_cancel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1074 struct NeighbourMapEntry *n = cls;
1076 n->ats_suggest = GNUNET_SCHEDULER_NO_TASK;
1078 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1079 " ATS did not suggested address to connect to peer `%s'\n",
1080 GNUNET_i2s (&n->id));
1082 disconnect_neighbour (n);
1086 * Cleanup the neighbours subsystem.
1089 GST_neighbours_stop ()
1091 // This can happen during shutdown
1092 if (neighbours == NULL)
1097 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &disconnect_all_neighbours,
1099 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
1100 // GNUNET_assert (neighbours_connected == 0);
1102 callback_cls = NULL;
1103 connect_notify_cb = NULL;
1104 disconnect_notify_cb = NULL;
1107 struct ContinutionContext
1109 struct GNUNET_HELLO_Address *address;
1111 struct Session *session;
1114 static void send_outbound_quota (const struct GNUNET_PeerIdentity *target, struct GNUNET_BANDWIDTH_Value32NBO quota)
1116 struct QuotaSetMessage q_msg;
1118 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1119 "Sending outbound quota of %u Bps for peer `%s' to all clients\n",
1120 ntohl (quota.value__), GNUNET_i2s (target));
1122 q_msg.header.size = htons (sizeof (struct QuotaSetMessage));
1123 q_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA);
1124 q_msg.quota = quota;
1125 q_msg.peer = (*target);
1126 GST_clients_broadcast (&q_msg.header, GNUNET_NO);
1130 * We tried to send a SESSION_CONNECT message to another peer. If this
1131 * succeeded, we change the state. If it failed, we should tell
1132 * ATS to not use this address anymore (until it is re-validated).
1134 * @param cls the 'struct GNUNET_HELLO_Address' of the address that was tried
1135 * @param success GNUNET_OK on success
1138 send_connect_continuation (void *cls, const struct GNUNET_PeerIdentity *target,
1141 struct ContinutionContext * cc = cls;
1142 struct NeighbourMapEntry *n = lookup_neighbour (&cc->address->peer);
1144 if (GNUNET_YES != success)
1146 GNUNET_assert (strlen(cc->address->transport_name) > 0);
1147 GNUNET_ATS_address_destroyed (GST_ats, cc->address, cc->session);
1149 if ( (NULL == neighbours) ||
1151 (n->state == S_DISCONNECT))
1153 GNUNET_HELLO_address_free (cc->address);
1158 if ((GNUNET_YES == success) &&
1159 ((n->state == S_NOT_CONNECTED) || (n->state == S_CONNECT_SENT)))
1161 change_state (n, S_CONNECT_SENT);
1162 GNUNET_HELLO_address_free (cc->address);
1167 if ((GNUNET_NO == success) &&
1168 ((n->state == S_NOT_CONNECTED) || (n->state == S_CONNECT_SENT)))
1171 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1172 "Failed to send CONNECT_MSG to peer `%4s' with address '%s' session %p, asking ATS for new address \n",
1173 GNUNET_i2s (&n->id),
1174 GST_plugins_a2s (n->address),
1177 change_state (n, S_NOT_CONNECTED);
1178 if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
1179 GNUNET_SCHEDULER_cancel (n->ats_suggest);
1181 GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, &ats_suggest_cancel,
1183 GNUNET_ATS_suggest_address (GST_ats, &n->id);
1185 GNUNET_HELLO_address_free (cc->address);
1190 * We tried to switch addresses with an peer already connected. If it failed,
1191 * we should tell ATS to not use this address anymore (until it is re-validated).
1193 * @param cls the 'struct NeighbourMapEntry'
1194 * @param success GNUNET_OK on success
1197 send_switch_address_continuation (void *cls,
1198 const struct GNUNET_PeerIdentity *target,
1201 struct ContinutionContext * cc = cls;
1202 struct NeighbourMapEntry *n;
1204 if (neighbours == NULL)
1206 GNUNET_HELLO_address_free (cc->address);
1208 return; /* neighbour is going away */
1211 n = lookup_neighbour(&cc->address->peer);
1212 if ((n == NULL) || (is_disconnecting (n)))
1214 GNUNET_HELLO_address_free (cc->address);
1216 return; /* neighbour is going away */
1219 GNUNET_assert ((n->state == S_CONNECTED) || (n->state == S_FAST_RECONNECT));
1220 if (GNUNET_YES != success)
1223 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1224 "Failed to switch connected peer `%s' to address '%s' session %X, asking ATS for new address \n",
1225 GNUNET_i2s (&n->id),
1226 GST_plugins_a2s (n->address), n->session);
1228 GNUNET_assert (strlen(cc->address->transport_name) > 0);
1229 GNUNET_ATS_address_destroyed (GST_ats, cc->address, cc->session);
1231 if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
1232 GNUNET_SCHEDULER_cancel (n->ats_suggest);
1234 GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel,
1236 GNUNET_ATS_suggest_address (GST_ats, &n->id);
1237 GNUNET_HELLO_address_free (cc->address);
1241 /* Tell ATS that switching addresses was successful */
1244 if (n->address_state == FRESH)
1246 GST_validation_set_address_use (&n->id,
1250 GNUNET_ATS_address_update (GST_ats, cc->address, cc->session, NULL, 0);
1251 GNUNET_ATS_address_in_use (GST_ats, cc->address, cc->session, GNUNET_YES);
1252 n->address_state = USED;
1255 case S_FAST_RECONNECT:
1257 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1258 "Successful fast reconnect to peer `%s'\n", GNUNET_i2s (&n->id));
1260 change_state (n, S_CONNECTED);
1261 neighbours_connected++;
1262 GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), 1,
1265 if (n->address_state == FRESH)
1267 GST_validation_set_address_use (&n->id,
1271 GNUNET_ATS_address_update (GST_ats, cc->address, cc->session, NULL, 0);
1272 GNUNET_ATS_address_in_use (GST_ats, cc->address, cc->session, GNUNET_YES);
1273 n->address_state = USED;
1276 if (n->keepalive_task == GNUNET_SCHEDULER_NO_TASK)
1277 n->keepalive_task = GNUNET_SCHEDULER_add_now (&neighbour_keepalive_task, n);
1279 /* Updating quotas */
1280 GST_neighbours_set_incoming_quota (&n->id, n->bandwidth_in);
1281 send_outbound_quota(target, n->bandwidth_out);
1286 GNUNET_HELLO_address_free (cc->address);
1291 * We tried to send a SESSION_CONNECT message to another peer. If this
1292 * succeeded, we change the state. If it failed, we should tell
1293 * ATS to not use this address anymore (until it is re-validated).
1295 * @param cls the 'struct NeighbourMapEntry'
1296 * @param success GNUNET_OK on success
1299 send_connect_ack_continuation (void *cls,
1300 const struct GNUNET_PeerIdentity *target,
1303 struct ContinutionContext * cc = cls;
1304 struct NeighbourMapEntry *n;
1306 if (neighbours == NULL)
1308 GNUNET_HELLO_address_free (cc->address);
1310 return; /* neighbour is going away */
1313 n = lookup_neighbour(&cc->address->peer);
1314 if ((n == NULL) || (is_disconnecting (n)))
1316 GNUNET_HELLO_address_free (cc->address);
1318 return; /* neighbour is going away */
1321 if (GNUNET_YES == success)
1323 GNUNET_HELLO_address_free (cc->address);
1325 return; /* sending successful */
1328 /* sending failed, ask for next address */
1330 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1331 "Failed to send CONNECT_MSG to peer `%4s' with address '%s' session %X, asking ATS for new address \n",
1332 GNUNET_i2s (&n->id),
1333 GST_plugins_a2s (n->address),
1336 change_state (n, S_NOT_CONNECTED);
1337 GNUNET_assert (strlen(cc->address->transport_name) > 0);
1338 GNUNET_ATS_address_destroyed (GST_ats, cc->address, cc->session);
1340 if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
1341 GNUNET_SCHEDULER_cancel (n->ats_suggest);
1343 GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel,
1345 GNUNET_ATS_suggest_address (GST_ats, &n->id);
1346 GNUNET_HELLO_address_free (cc->address);
1351 * For an existing neighbour record, set the active connection to
1352 * the given address.
1354 * @param peer identity of the peer to switch the address for
1355 * @param address address of the other peer, NULL if other peer
1357 * @param session session to use (or NULL)
1358 * @param ats performance data
1359 * @param ats_count number of entries in ats
1360 * @return GNUNET_YES if we are currently connected, GNUNET_NO if the
1361 * connection is not up (yet)
1364 GST_neighbours_switch_to_address_3way (const struct GNUNET_PeerIdentity *peer,
1365 const struct GNUNET_HELLO_Address *address,
1366 struct Session *session,
1367 const struct GNUNET_ATS_Information *ats,
1369 struct GNUNET_BANDWIDTH_Value32NBO
1371 struct GNUNET_BANDWIDTH_Value32NBO
1374 struct NeighbourMapEntry *n;
1375 struct SessionConnectMessage connect_msg;
1376 struct ContinutionContext * cc;
1380 if (neighbours == NULL)
1382 /* This can happen during shutdown */
1385 n = lookup_neighbour (peer);
1388 if (n->state == S_DISCONNECT)
1390 /* We are disconnecting, nothing to do here */
1393 GNUNET_assert (address->transport_name != NULL);
1394 if ( (session == NULL) && (0 == address->address_length) )
1396 GNUNET_break_op (0);
1397 /* FIXME: is this actually possible? When does this happen? */
1398 if (strlen(address->transport_name) > 0)
1399 GNUNET_ATS_address_destroyed (GST_ats, address, session);
1400 GNUNET_ATS_suggest_address (GST_ats, peer);
1404 /* checks successful and neighbour != NULL */
1406 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1407 "ATS tells us to switch to address '%s' session %p for peer `%s' in state `%s'\n",
1408 GST_plugins_a2s (address),
1411 print_state(n->state));
1413 if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
1415 GNUNET_SCHEDULER_cancel (n->ats_suggest);
1416 n->ats_suggest = GNUNET_SCHEDULER_NO_TASK;
1418 /* do not switch addresses just update quotas */
1419 if ( (n->state == S_CONNECTED) &&
1420 (NULL != n->address) &&
1421 (0 == GNUNET_HELLO_address_cmp (address,
1423 (n->session == session) )
1425 n->bandwidth_in = bandwidth_in;
1426 n->bandwidth_out = bandwidth_out;
1427 GST_neighbours_set_incoming_quota (&n->id, n->bandwidth_in);
1428 send_outbound_quota(peer, n->bandwidth_out);
1431 if (n->state == S_CONNECTED)
1433 /* mark old address as no longer used */
1434 GNUNET_assert (NULL != n->address);
1435 if (n->address_state == USED)
1437 GST_validation_set_address_use (&n->id,
1441 GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_NO);
1442 n->address_state = UNUSED;
1447 /* set new address */
1448 if (NULL != n->address)
1449 GNUNET_HELLO_address_free (n->address);
1450 n->address = GNUNET_HELLO_address_copy (address);
1451 n->address_state = FRESH;
1452 n->session = session;
1453 n->bandwidth_in = bandwidth_in;
1454 n->bandwidth_out = bandwidth_out;
1455 GNUNET_SCHEDULER_cancel (n->timeout_task);
1457 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1458 &neighbour_timeout_task, n);
1461 case S_NOT_CONNECTED:
1462 case S_CONNECT_SENT:
1463 msg_len = sizeof (struct SessionConnectMessage);
1464 connect_msg.header.size = htons (msg_len);
1465 connect_msg.header.type =
1466 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT);
1467 connect_msg.reserved = htonl (0);
1468 connect_msg.timestamp =
1469 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
1471 cc = GNUNET_malloc(sizeof (struct ContinutionContext));
1472 cc->session = session;
1473 cc->address = GNUNET_HELLO_address_copy (address);
1475 send_with_plugin (peer, (const char *) &connect_msg, msg_len,
1476 UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL, session,
1477 address, GNUNET_YES,
1478 &send_connect_continuation,
1481 case S_CONNECT_RECV:
1482 /* We received a CONNECT message and asked ATS for an address */
1483 msg_len = sizeof (struct SessionConnectMessage);
1484 connect_msg.header.size = htons (msg_len);
1485 connect_msg.header.type =
1486 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT_ACK);
1487 connect_msg.reserved = htonl (0);
1488 connect_msg.timestamp =
1489 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
1490 cc = GNUNET_malloc(sizeof (struct ContinutionContext));
1491 cc->session = session;
1492 cc->address = GNUNET_HELLO_address_copy (address);
1494 send_with_plugin (&n->id, (const void *) &connect_msg, msg_len,
1495 UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL, session,
1496 address, GNUNET_YES,
1497 &send_connect_ack_continuation, cc);
1500 case S_FAST_RECONNECT:
1501 /* connected peer is switching addresses or tries fast reconnect*/
1502 msg_len = sizeof (struct SessionConnectMessage);
1503 connect_msg.header.size = htons (msg_len);
1504 connect_msg.header.type =
1505 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT);
1506 connect_msg.reserved = htonl (0);
1507 connect_msg.timestamp =
1508 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
1509 cc = GNUNET_malloc(sizeof (struct ContinutionContext));
1510 cc->session = session;
1511 cc->address = GNUNET_HELLO_address_copy (address);
1513 send_with_plugin (peer, (const char *) &connect_msg, msg_len,
1514 UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL, session,
1515 address, GNUNET_YES,
1516 &send_switch_address_continuation, cc);
1517 if (ret == GNUNET_SYSERR)
1519 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1520 "Failed to send CONNECT_MESSAGE to `%4s' using address '%s' session %X\n",
1522 GST_plugins_a2s (address), session);
1526 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1527 "Invalid connection state to switch addresses %u \n", n->state);
1528 GNUNET_break_op (0);
1535 * Obtain current latency information for the given neighbour.
1538 * @return observed latency of the address, FOREVER if the address was
1539 * never successfully validated
1541 struct GNUNET_TIME_Relative
1542 GST_neighbour_get_latency (const struct GNUNET_PeerIdentity *peer)
1544 struct NeighbourMapEntry *n;
1546 n = lookup_neighbour (peer);
1548 ( (n->address == NULL) && (n->session == NULL) ) )
1549 return GNUNET_TIME_UNIT_FOREVER_REL;
1556 * Create an entry in the neighbour map for the given peer
1558 * @param peer peer to create an entry for
1559 * @return new neighbour map entry
1561 static struct NeighbourMapEntry *
1562 setup_neighbour (const struct GNUNET_PeerIdentity *peer)
1564 struct NeighbourMapEntry *n;
1567 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1568 "Unknown peer `%s', creating new neighbour\n", GNUNET_i2s (peer));
1570 n = GNUNET_malloc (sizeof (struct NeighbourMapEntry));
1572 n->state = S_NOT_CONNECTED;
1573 n->latency = GNUNET_TIME_relative_get_forever();
1574 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
1575 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
1576 MAX_BANDWIDTH_CARRY_S);
1578 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1579 &neighbour_timeout_task, n);
1580 GNUNET_assert (GNUNET_OK ==
1581 GNUNET_CONTAINER_multihashmap_put (neighbours,
1582 &n->id.hashPubKey, n,
1583 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1589 * Try to create a connection to the given target (eventually).
1591 * @param target peer to try to connect to
1594 GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target)
1596 struct NeighbourMapEntry *n;
1598 // This can happen during shutdown
1599 if (neighbours == NULL)
1604 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to connect to peer `%s'\n",
1605 GNUNET_i2s (target));
1608 memcmp (target, &GST_my_identity, sizeof (struct GNUNET_PeerIdentity)))
1613 n = lookup_neighbour (target);
1617 if ((S_CONNECTED == n->state) || (is_connecting (n)))
1618 return; /* already connecting or connected */
1619 if (is_disconnecting (n))
1620 change_state (n, S_NOT_CONNECTED);
1625 n = setup_neighbour (target);
1627 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1628 "Asking ATS for suggested address to connect to peer `%s'\n",
1629 GNUNET_i2s (&n->id));
1632 GNUNET_ATS_suggest_address (GST_ats, &n->id);
1636 * Test if we're connected to the given peer.
1638 * @param target peer to test
1639 * @return GNUNET_YES if we are connected, GNUNET_NO if not
1642 GST_neighbours_test_connected (const struct GNUNET_PeerIdentity *target)
1644 struct NeighbourMapEntry *n;
1646 // This can happen during shutdown
1647 if (neighbours == NULL)
1652 n = lookup_neighbour (target);
1654 if ((NULL == n) || (S_CONNECTED != n->state))
1655 return GNUNET_NO; /* not connected */
1660 * A session was terminated. Take note.
1662 * @param peer identity of the peer where the session died
1663 * @param session session that is gone
1666 GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer,
1667 struct Session *session)
1669 struct NeighbourMapEntry *n;
1671 if (neighbours == NULL)
1673 /* This can happen during shutdown */
1678 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Session %X to peer `%s' ended \n",
1679 session, GNUNET_i2s (peer));
1682 n = lookup_neighbour (peer);
1685 if (session != n->session)
1686 return; /* doesn't affect us */
1687 if (n->state == S_CONNECTED)
1689 if (n->address_state == USED)
1691 GST_validation_set_address_use (&n->id,
1695 GNUNET_ATS_address_in_use (GST_ats,n->address, n->session, GNUNET_NO);
1696 n->address_state = UNUSED;
1700 if (NULL != n->address)
1702 GNUNET_HELLO_address_free (n->address);
1707 /* not connected anymore anyway, shouldn't matter */
1708 if (S_CONNECTED != n->state)
1711 /* connected, try fast reconnect */
1713 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1714 "Trying fast reconnect to peer `%s'\n", GNUNET_i2s (peer));
1716 change_state (n, S_FAST_RECONNECT);
1717 GNUNET_assert (neighbours_connected > 0);
1718 neighbours_connected--;
1720 if (n->keepalive_task != GNUNET_SCHEDULER_NO_TASK)
1722 GNUNET_SCHEDULER_cancel (n->keepalive_task);
1723 n->keepalive_task = GNUNET_SCHEDULER_NO_TASK;
1726 /* We are connected, so ask ATS to switch addresses */
1727 GNUNET_SCHEDULER_cancel (n->timeout_task);
1729 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_DISCONNECT_SESSION_TIMEOUT,
1730 &neighbour_timeout_task, n);
1731 /* try QUICKLY to re-establish a connection, reduce timeout! */
1732 if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
1733 GNUNET_SCHEDULER_cancel (n->ats_suggest);
1735 GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, &ats_suggest_cancel,
1737 GNUNET_ATS_suggest_address (GST_ats, peer);
1742 * Transmit a message to the given target using the active connection.
1744 * @param target destination
1745 * @param msg message to send
1746 * @param msg_size number of bytes in msg
1747 * @param timeout when to fail with timeout
1748 * @param cont function to call when done
1749 * @param cont_cls closure for 'cont'
1752 GST_neighbours_send (const struct GNUNET_PeerIdentity *target, const void *msg,
1753 size_t msg_size, struct GNUNET_TIME_Relative timeout,
1754 GST_NeighbourSendContinuation cont, void *cont_cls)
1756 struct NeighbourMapEntry *n;
1757 struct MessageQueue *mq;
1759 // This can happen during shutdown
1760 if (neighbours == NULL)
1765 n = lookup_neighbour (target);
1766 if ((n == NULL) || (!is_connected (n)))
1768 GNUNET_STATISTICS_update (GST_stats,
1770 ("# messages not sent (no such peer or not connected)"),
1774 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1775 "Could not send message to peer `%s': unknown neighbour",
1776 GNUNET_i2s (target));
1777 else if (!is_connected (n))
1778 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1779 "Could not send message to peer `%s': not connected\n",
1780 GNUNET_i2s (target));
1783 cont (cont_cls, GNUNET_SYSERR);
1787 if ((n->session == NULL) && (n->address == NULL) )
1789 GNUNET_STATISTICS_update (GST_stats,
1791 ("# messages not sent (no such peer or not connected)"),
1794 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1795 "Could not send message to peer `%s': no address available\n",
1796 GNUNET_i2s (target));
1800 cont (cont_cls, GNUNET_SYSERR);
1804 GNUNET_assert (msg_size >= sizeof (struct GNUNET_MessageHeader));
1805 GNUNET_STATISTICS_update (GST_stats,
1807 ("# bytes in message queue for other peers"),
1808 msg_size, GNUNET_NO);
1809 mq = GNUNET_malloc (sizeof (struct MessageQueue) + msg_size);
1811 mq->cont_cls = cont_cls;
1812 /* FIXME: this memcpy can be up to 7% of our total runtime! */
1813 memcpy (&mq[1], msg, msg_size);
1814 mq->message_buf = (const char *) &mq[1];
1815 mq->message_buf_size = msg_size;
1816 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1817 GNUNET_CONTAINER_DLL_insert_tail (n->messages_head, n->messages_tail, mq);
1819 if ((GNUNET_SCHEDULER_NO_TASK == n->transmission_task) &&
1820 (NULL == n->is_active))
1821 n->transmission_task = GNUNET_SCHEDULER_add_now (&transmission_task, n);
1826 * We have received a message from the given sender. How long should
1827 * we delay before receiving more? (Also used to keep the peer marked
1830 * @param sender sender of the message
1831 * @param size size of the message
1832 * @param do_forward set to GNUNET_YES if the message should be forwarded to clients
1833 * GNUNET_NO if the neighbour is not connected or violates the quota,
1834 * GNUNET_SYSERR if the connection is not fully up yet
1835 * @return how long to wait before reading more from this sender
1837 struct GNUNET_TIME_Relative
1838 GST_neighbours_calculate_receive_delay (const struct GNUNET_PeerIdentity
1839 *sender, ssize_t size, int *do_forward)
1841 struct NeighbourMapEntry *n;
1842 struct GNUNET_TIME_Relative ret;
1844 // This can happen during shutdown
1845 if (neighbours == NULL)
1847 return GNUNET_TIME_UNIT_FOREVER_REL;
1850 n = lookup_neighbour (sender);
1853 GST_neighbours_try_connect (sender);
1854 n = lookup_neighbour (sender);
1857 GNUNET_STATISTICS_update (GST_stats,
1859 ("# messages discarded due to lack of neighbour record"),
1861 *do_forward = GNUNET_NO;
1862 return GNUNET_TIME_UNIT_ZERO;
1865 if (!is_connected (n))
1867 *do_forward = GNUNET_SYSERR;
1868 return GNUNET_TIME_UNIT_ZERO;
1870 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, size))
1872 n->quota_violation_count++;
1874 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1875 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
1876 n->in_tracker.available_bytes_per_s__,
1877 n->quota_violation_count);
1879 /* Discount 32k per violation */
1880 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, -32 * 1024);
1884 if (n->quota_violation_count > 0)
1886 /* try to add 32k back */
1887 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, 32 * 1024);
1888 n->quota_violation_count--;
1891 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
1893 GNUNET_STATISTICS_update (GST_stats,
1895 ("# bandwidth quota violations by other peers"),
1897 *do_forward = GNUNET_NO;
1898 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
1900 *do_forward = GNUNET_YES;
1901 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 32 * 1024);
1902 if (ret.rel_value > 0)
1905 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1906 "Throttling read (%llu bytes excess at %u b/s), waiting %llu ms before reading more.\n",
1907 (unsigned long long) n->in_tracker.
1908 consumption_since_last_update__,
1909 (unsigned int) n->in_tracker.available_bytes_per_s__,
1910 (unsigned long long) ret.rel_value);
1912 GNUNET_STATISTICS_update (GST_stats,
1913 gettext_noop ("# ms throttling suggested"),
1914 (int64_t) ret.rel_value, GNUNET_NO);
1921 * Keep the connection to the given neighbour alive longer,
1922 * we received a KEEPALIVE (or equivalent).
1924 * @param neighbour neighbour to keep alive
1927 GST_neighbours_keepalive (const struct GNUNET_PeerIdentity *neighbour)
1929 struct NeighbourMapEntry *n;
1931 // This can happen during shutdown
1932 if (neighbours == NULL)
1937 n = lookup_neighbour (neighbour);
1940 GNUNET_STATISTICS_update (GST_stats,
1942 ("# KEEPALIVE messages discarded (not connected)"),
1946 GNUNET_SCHEDULER_cancel (n->timeout_task);
1948 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1949 &neighbour_timeout_task, n);
1951 /* send reply to measure latency */
1952 if (S_CONNECTED != n->state)
1955 struct GNUNET_MessageHeader m;
1956 m.size = htons (sizeof (struct GNUNET_MessageHeader));
1957 m.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE_RESPONSE);
1959 send_with_plugin (&n->id, (const void *) &m, sizeof (m),
1960 UINT32_MAX /* priority */ ,
1961 GNUNET_TIME_UNIT_FOREVER_REL, n->session, n->address,
1962 GNUNET_YES, NULL, NULL);
1966 * We received a KEEP_ALIVE_RESPONSE message and use this to calculate latency
1969 * @param neighbour neighbour to keep alive
1972 GST_neighbours_keepalive_response (const struct GNUNET_PeerIdentity *neighbour,
1973 const struct GNUNET_ATS_Information * ats,
1976 struct NeighbourMapEntry *n;
1977 struct GNUNET_ATS_Information * ats_new;
1980 if (neighbours == NULL)
1982 // This can happen during shutdown
1986 n = lookup_neighbour (neighbour);
1989 GNUNET_STATISTICS_update (GST_stats,
1991 ("# KEEPALIVE_RESPONSE messages discarded (not connected)"),
1995 if (n->expect_latency_response != GNUNET_YES)
1997 GNUNET_STATISTICS_update (GST_stats,
1999 ("# KEEPALIVE_RESPONSE messages discarded (not expected)"),
2003 n->expect_latency_response = GNUNET_NO;
2005 GNUNET_assert (n->keep_alive_sent.abs_value != GNUNET_TIME_absolute_get_zero().abs_value);
2006 n->latency = GNUNET_TIME_absolute_get_difference(n->keep_alive_sent, GNUNET_TIME_absolute_get());
2008 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2009 "Latency for peer `%s' is %llu ms\n",
2010 GNUNET_i2s (&n->id), n->latency.rel_value);
2014 if (n->latency.rel_value == GNUNET_TIME_relative_get_forever().rel_value)
2016 GNUNET_ATS_address_update (GST_ats, n->address, n->session, ats, ats_count);
2020 ats_new = GNUNET_malloc (sizeof (struct GNUNET_ATS_Information) * (ats_count + 1));
2021 memcpy (ats_new, ats, sizeof (struct GNUNET_ATS_Information) * ats_count);
2024 ats_new[ats_count].type = htonl (GNUNET_ATS_QUALITY_NET_DELAY);
2025 if (n->latency.rel_value > UINT32_MAX)
2026 latency = UINT32_MAX;
2028 latency = n->latency.rel_value;
2029 ats_new[ats_count].value = htonl (latency);
2031 GNUNET_ATS_address_update (GST_ats, n->address, n->session, ats_new, ats_count + 1);
2032 GNUNET_free (ats_new);
2038 * Change the incoming quota for the given peer.
2040 * @param neighbour identity of peer to change qutoa for
2041 * @param quota new quota
2044 GST_neighbours_set_incoming_quota (const struct GNUNET_PeerIdentity *neighbour,
2045 struct GNUNET_BANDWIDTH_Value32NBO quota)
2047 struct NeighbourMapEntry *n;
2049 // This can happen during shutdown
2050 if (neighbours == NULL)
2055 n = lookup_neighbour (neighbour);
2058 GNUNET_STATISTICS_update (GST_stats,
2060 ("# SET QUOTA messages ignored (no such peer)"),
2065 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2066 "Setting inbound quota of %u Bps for peer `%s' to all clients\n",
2067 ntohl (quota.value__), GNUNET_i2s (&n->id));
2069 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker, quota);
2070 if (0 != ntohl (quota.value__))
2073 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s' due to `%s'\n",
2074 GNUNET_i2s (&n->id), "SET_QUOTA");
2076 if (is_connected (n))
2077 GNUNET_STATISTICS_update (GST_stats,
2078 gettext_noop ("# disconnects due to quota of 0"),
2080 disconnect_neighbour (n);
2085 * Closure for the neighbours_iterate function.
2087 struct IteratorContext
2090 * Function to call on each connected neighbour.
2092 GST_NeighbourIterator cb;
2102 * Call the callback from the closure for each connected neighbour.
2104 * @param cls the 'struct IteratorContext'
2105 * @param key the hash of the public key of the neighbour
2106 * @param value the 'struct NeighbourMapEntry'
2107 * @return GNUNET_OK (continue to iterate)
2110 neighbours_iterate (void *cls, const GNUNET_HashCode * key, void *value)
2112 struct IteratorContext *ic = cls;
2113 struct NeighbourMapEntry *n = value;
2115 if (!is_connected (n))
2118 ic->cb (ic->cb_cls, &n->id, NULL, 0, n->address);
2124 * Iterate over all connected neighbours.
2126 * @param cb function to call
2127 * @param cb_cls closure for cb
2130 GST_neighbours_iterate (GST_NeighbourIterator cb, void *cb_cls)
2132 struct IteratorContext ic;
2134 // This can happen during shutdown
2135 if (neighbours == NULL)
2142 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &neighbours_iterate, &ic);
2146 * If we have an active connection to the given target, it must be shutdown.
2148 * @param target peer to disconnect from
2151 GST_neighbours_force_disconnect (const struct GNUNET_PeerIdentity *target)
2153 struct NeighbourMapEntry *n;
2155 // This can happen during shutdown
2156 if (neighbours == NULL)
2161 n = lookup_neighbour (target);
2163 return; /* not active */
2164 disconnect_neighbour (n);
2169 * We received a disconnect message from the given peer,
2170 * validate and process.
2172 * @param peer sender of the message
2173 * @param msg the disconnect message
2176 GST_neighbours_handle_disconnect_message (const struct GNUNET_PeerIdentity
2178 const struct GNUNET_MessageHeader
2181 struct NeighbourMapEntry *n;
2182 const struct SessionDisconnectMessage *sdm;
2186 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2187 "Received DISCONNECT message from peer `%s'\n",
2191 if (ntohs (msg->size) != sizeof (struct SessionDisconnectMessage))
2193 // GNUNET_break_op (0);
2194 GNUNET_STATISTICS_update (GST_stats,
2196 ("# disconnect messages ignored (old format)"), 1,
2200 sdm = (const struct SessionDisconnectMessage *) msg;
2201 n = lookup_neighbour (peer);
2203 return; /* gone already */
2204 if (GNUNET_TIME_absolute_ntoh (sdm->timestamp).abs_value <=
2205 n->connect_ts.abs_value)
2207 GNUNET_STATISTICS_update (GST_stats,
2209 ("# disconnect messages ignored (timestamp)"), 1,
2213 GNUNET_CRYPTO_hash (&sdm->public_key,
2214 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2216 if (0 != memcmp (peer, &hc, sizeof (struct GNUNET_PeerIdentity)))
2218 GNUNET_break_op (0);
2221 if (ntohl (sdm->purpose.size) !=
2222 sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
2223 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) +
2224 sizeof (struct GNUNET_TIME_AbsoluteNBO))
2226 GNUNET_break_op (0);
2230 GNUNET_CRYPTO_rsa_verify
2231 (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT, &sdm->purpose,
2232 &sdm->signature, &sdm->public_key))
2234 GNUNET_break_op (0);
2237 GST_neighbours_force_disconnect (peer);
2242 * We received a 'SESSION_CONNECT_ACK' message from the other peer.
2243 * Consider switching to it.
2245 * @param message possibly a 'struct SessionConnectMessage' (check format)
2246 * @param peer identity of the peer to switch the address for
2247 * @param address address of the other peer, NULL if other peer
2249 * @param session session to use (or NULL)
2250 * @param ats performance data
2251 * @param ats_count number of entries in ats
2254 GST_neighbours_handle_connect_ack (const struct GNUNET_MessageHeader *message,
2255 const struct GNUNET_PeerIdentity *peer,
2256 const struct GNUNET_HELLO_Address *address,
2257 struct Session *session,
2258 const struct GNUNET_ATS_Information *ats,
2261 const struct SessionConnectMessage *scm;
2262 struct GNUNET_MessageHeader msg;
2263 struct NeighbourMapEntry *n;
2268 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2269 "Received CONNECT_ACK message from peer `%s'\n",
2273 if (ntohs (message->size) != sizeof (struct SessionConnectMessage))
2275 GNUNET_break_op (0);
2278 scm = (const struct SessionConnectMessage *) message;
2279 GNUNET_break_op (ntohl (scm->reserved) == 0);
2280 n = lookup_neighbour (peer);
2283 /* we did not send 'CONNECT' (how could we? no record for this peer!) */
2284 GNUNET_break_op (0);
2290 * ((n->state != S_CONNECT_RECV) && (n->address != NULL)):
2292 * We also received an CONNECT message, switched from SENDT to RECV and
2293 * ATS already suggested us an address after a successful blacklist check
2295 if ((n->state != S_CONNECT_SENT) && ((n->state != S_CONNECT_RECV) && (n->address != NULL)))
2297 GNUNET_STATISTICS_update (GST_stats,
2298 gettext_noop ("# unexpected CONNECT_ACK messages"), 1,
2303 change_state (n, S_CONNECTED);
2305 if (NULL != session)
2307 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2309 "Giving ATS session %p of plugin %s for peer %s\n",
2310 session, address->transport_name, GNUNET_i2s (peer));
2312 GNUNET_ATS_address_update (GST_ats, address, session, ats, ats_count);
2313 GNUNET_assert (NULL != n->address);
2314 if (n->address_state == FRESH)
2316 GST_validation_set_address_use (&n->id,
2320 GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_YES);
2321 n->address_state = USED;
2324 GST_neighbours_set_incoming_quota (&n->id, n->bandwidth_in);
2326 /* send ACK (ACK) */
2327 msg_len = sizeof (msg);
2328 msg.size = htons (msg_len);
2329 msg.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK);
2332 send_with_plugin (&n->id, (const char *) &msg, msg_len, UINT32_MAX,
2333 GNUNET_TIME_UNIT_FOREVER_REL, n->session,
2334 n->address, GNUNET_YES, NULL,
2337 if (ret == GNUNET_SYSERR)
2338 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2339 "Failed to send SESSION_ACK to `%4s' using address '%s' session %X\n",
2340 GNUNET_i2s (&n->id),
2341 GST_plugins_a2s (n->address), n->session);
2344 if (n->keepalive_task == GNUNET_SCHEDULER_NO_TASK)
2345 n->keepalive_task = GNUNET_SCHEDULER_add_now (&neighbour_keepalive_task, n);
2347 neighbours_connected++;
2348 GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), 1,
2351 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2352 "Notify about connect of `%4s' using address '%s' session %X LINE %u\n",
2353 GNUNET_i2s (&n->id),
2354 GST_plugins_a2s (n->address), n->session,
2357 connect_notify_cb (callback_cls, &n->id, ats, ats_count);
2358 send_outbound_quota(peer, n->bandwidth_out);
2364 GST_neighbours_handle_ack (const struct GNUNET_MessageHeader *message,
2365 const struct GNUNET_PeerIdentity *peer,
2366 const struct GNUNET_HELLO_Address *address,
2367 struct Session *session,
2368 const struct GNUNET_ATS_Information *ats,
2371 struct NeighbourMapEntry *n;
2374 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2375 "Received ACK message from peer `%s'\n",
2379 if (ntohs (message->size) != sizeof (struct GNUNET_MessageHeader))
2381 GNUNET_break_op (0);
2384 n = lookup_neighbour (peer);
2387 send_disconnect (peer, address,
2392 if (S_CONNECTED == n->state)
2394 if (!is_connecting(n))
2396 GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# unexpected ACK messages"), 1,
2400 change_state (n, S_CONNECTED);
2401 if (NULL != session)
2402 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2404 "Giving ATS session %p of plugin %s for peer %s\n",
2405 session, address->transport_name, GNUNET_i2s (peer));
2406 GNUNET_ATS_address_update (GST_ats, address, session, ats, ats_count);
2407 GNUNET_assert (n->address != NULL);
2408 if (n->address_state == FRESH)
2410 GST_validation_set_address_use (&n->id,
2414 GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_YES);
2415 n->address_state = USED;
2418 neighbours_connected++;
2419 GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), 1,
2422 GST_neighbours_set_incoming_quota (&n->id, n->bandwidth_in);
2423 if (n->keepalive_task == GNUNET_SCHEDULER_NO_TASK)
2424 n->keepalive_task = GNUNET_SCHEDULER_add_now (&neighbour_keepalive_task, n);
2426 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2427 "Notify about connect of `%4s' using address '%s' session %X LINE %u\n",
2428 GNUNET_i2s (&n->id),
2429 GST_plugins_a2s (n->address), n->session,
2432 connect_notify_cb (callback_cls, &n->id, ats, ats_count);
2433 send_outbound_quota(peer, n->bandwidth_out);
2436 struct BlackListCheckContext
2438 struct GNUNET_ATS_Information *ats;
2442 struct Session *session;
2444 struct GNUNET_HELLO_Address *address;
2446 struct GNUNET_TIME_Absolute ts;
2451 handle_connect_blacklist_cont (void *cls,
2452 const struct GNUNET_PeerIdentity *peer,
2455 struct NeighbourMapEntry *n;
2456 struct BlackListCheckContext *bcc = cls;
2459 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2460 "Blacklist check due to CONNECT message: `%s'\n",
2462 (result == GNUNET_OK) ? "ALLOWED" : "FORBIDDEN");
2466 if (GNUNET_OK != result)
2468 GNUNET_HELLO_address_free (bcc->address);
2473 n = lookup_neighbour (peer);
2475 n = setup_neighbour (peer);
2477 if (bcc->ts.abs_value > n->connect_ts.abs_value)
2479 if (NULL != bcc->session)
2480 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2482 "Giving ATS session %p of address `%s' for peer %s\n",
2484 GST_plugins_a2s (bcc->address),
2486 /* Tell ATS about the session, so ATS can suggest it if it likes it. */
2488 GNUNET_ATS_address_update (GST_ats,
2493 n->connect_ts = bcc->ts;
2496 GNUNET_HELLO_address_free (bcc->address);
2499 if (n->state != S_CONNECT_RECV)
2500 change_state (n, S_CONNECT_RECV);
2502 /* Ask ATS for an address to connect via that address */
2503 if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
2504 GNUNET_SCHEDULER_cancel (n->ats_suggest);
2506 GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel,
2508 GNUNET_ATS_suggest_address (GST_ats, peer);
2512 * We received a 'SESSION_CONNECT' message from the other peer.
2513 * Consider switching to it.
2515 * @param message possibly a 'struct SessionConnectMessage' (check format)
2516 * @param peer identity of the peer to switch the address for
2517 * @param address address of the other peer, NULL if other peer
2519 * @param session session to use (or NULL)
2520 * @param ats performance data
2521 * @param ats_count number of entries in ats (excluding 0-termination)
2524 GST_neighbours_handle_connect (const struct GNUNET_MessageHeader *message,
2525 const struct GNUNET_PeerIdentity *peer,
2526 const struct GNUNET_HELLO_Address *address,
2527 struct Session *session,
2528 const struct GNUNET_ATS_Information *ats,
2531 const struct SessionConnectMessage *scm;
2532 struct NeighbourMapEntry *n;
2533 struct BlackListCheckContext *bcc = NULL;
2536 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2537 "Received CONNECT message from peer `%s'\n", GNUNET_i2s (peer));
2540 if (ntohs (message->size) != sizeof (struct SessionConnectMessage))
2542 GNUNET_break_op (0);
2546 scm = (const struct SessionConnectMessage *) message;
2547 GNUNET_break_op (ntohl (scm->reserved) == 0);
2549 n = lookup_neighbour (peer);
2551 (S_CONNECTED == n->state) )
2553 /* connected peer switches addresses */
2554 GNUNET_ATS_address_update (GST_ats, address, session, ats, ats_count);
2558 /* we are not connected to this peer */
2559 /* do blacklist check */
2561 GNUNET_malloc (sizeof (struct BlackListCheckContext) +
2562 sizeof (struct GNUNET_ATS_Information) * (ats_count + 1));
2563 bcc->ts = GNUNET_TIME_absolute_ntoh (scm->timestamp);
2564 bcc->ats_count = ats_count + 1;
2565 bcc->address = GNUNET_HELLO_address_copy (address);
2566 bcc->session = session;
2567 bcc->ats = (struct GNUNET_ATS_Information *) &bcc[1];
2568 memcpy (bcc->ats, ats, sizeof (struct GNUNET_ATS_Information) * ats_count);
2569 bcc->ats[ats_count].type = htonl (GNUNET_ATS_QUALITY_NET_DELAY);
2570 bcc->ats[ats_count].value = htonl ((uint32_t) GST_neighbour_get_latency (peer).rel_value);
2571 GST_blacklist_test_allowed (peer, address->transport_name, handle_connect_blacklist_cont,
2576 /* end of file gnunet-service-transport_neighbours.c */