src: for every AGPL3.0 file, add SPDX identifier.
[oweals/gnunet.git] / src / transport / gnunet-service-transport_neighbours.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2010-2015 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21 /**
22  * @file transport/gnunet-service-transport_neighbours.c
23  * @brief neighbour management
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_ats_service.h"
28 #include "gnunet-service-transport_ats.h"
29 #include "gnunet-service-transport_neighbours.h"
30 #include "gnunet-service-transport_manipulation.h"
31 #include "gnunet-service-transport_plugins.h"
32 #include "gnunet-service-transport_validation.h"
33 #include "gnunet-service-transport.h"
34 #include "gnunet_peerinfo_service.h"
35 #include "gnunet_constants.h"
36 #include "transport.h"
37
38 /**
39  * Experimental option to ignore SessionQuotaMessages from
40  * the other peer.
41  */
42 #define IGNORE_INBOUND_QUOTA GNUNET_YES
43
44 /**
45  * Size of the neighbour hash map.
46  */
47 #define NEIGHBOUR_TABLE_SIZE 256
48
49 /**
50  * Time we give plugin to transmit DISCONNECT message before the
51  * neighbour entry self-destructs.
52  */
53 #define DISCONNECT_SENT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500)
54
55 /**
56  * How often must a peer violate bandwidth quotas before we start
57  * to simply drop its messages?
58  */
59 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
60
61 /**
62  * How long are we willing to wait for a response from ATS before timing out?
63  */
64 #define ATS_RESPONSE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
65
66 /**
67  * How long are we willing to wait for an ACK from the other peer before
68  * giving up on our connect operation?
69  */
70 #define SETUP_CONNECTION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
71
72 /**
73  * How long are we willing to wait for a successful reconnect if
74  * an existing connection went down?  Much shorter than the
75  * usual SETUP_CONNECTION_TIMEOUT as we do not inform the
76  * higher layers about the disconnect during this period.
77  */
78 #define FAST_RECONNECT_TIMEOUT GNUNET_TIME_UNIT_SECONDS
79
80 /**
81  * Interval to send utilization data
82  */
83 #define UTIL_TRANSMISSION_INTERVAL GNUNET_TIME_UNIT_SECONDS
84
85 /**
86  * State describing which kind a reply this neighbour should send
87  */
88 enum GST_ACK_State
89 {
90   /**
91    * We did not receive a SYN message for this neighbour
92    */
93   ACK_UNDEFINED = 0,
94
95   /**
96    * The neighbour received a SYN message and has to send a SYN_ACK
97    * as reply
98    */
99   ACK_SEND_SYN_ACK = 1,
100
101   /**
102    * The neighbour sent a SYN_ACK message and has to send a ACK
103    * as reply
104    */
105   ACK_SEND_ACK = 2
106 };
107
108
109 GNUNET_NETWORK_STRUCT_BEGIN
110
111 /**
112  * Message a peer sends to another to indicate that it intends to
113  * setup a connection/session for data exchange.  A 'SESSION_SYN'
114  * should be answered with a 'SESSION_SYN_ACK' with the same body
115  * to confirm.  A 'SESSION_SYN_ACK' should then be followed with
116  * a 'ACK'.  Once the 'ACK' is received, both peers
117  * should be connected.
118  */
119 struct TransportSynMessage
120 {
121   /**
122    * Header of type #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN
123    * or #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN_ACK
124    */
125   struct GNUNET_MessageHeader header;
126
127   /**
128    * Always zero.
129    */
130   uint32_t reserved GNUNET_PACKED;
131
132   /**
133    * Absolute time at the sender.  Only the most recent connect
134    * message implies which session is preferred by the sender.
135    */
136   struct GNUNET_TIME_AbsoluteNBO timestamp;
137
138 };
139
140
141 /**
142  * Message a peer sends to another when connected to indicate that a
143  * session is in use and the peer is still alive or to respond to a keep alive.
144  * A peer sends a message with type #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE
145  * to request a message with #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE_RESPONSE.
146  * When the keep alive response with type is received, transport service
147  * will call the respective plugin to update the session timeout
148  */
149 struct GNUNET_ATS_SessionKeepAliveMessage
150 {
151   /**
152    * Header of type #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE or
153    * #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE_RESPONSE.
154    */
155   struct GNUNET_MessageHeader header;
156
157   /**
158    * A nonce to identify the session the keep alive is used for
159    */
160   uint32_t nonce GNUNET_PACKED;
161 };
162
163
164 /**
165  * Message a peer sends to another when connected to indicate that
166  * the other peer should limit transmissions to the indicated
167  * quota.
168  */
169 struct GNUNET_ATS_SessionQuotaMessage
170 {
171   /**
172    * Header of type #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_QUOTA.
173    */
174   struct GNUNET_MessageHeader header;
175
176   /**
177    * Quota to use (for sending), in bytes per second.
178    */
179   uint32_t quota GNUNET_PACKED;
180 };
181
182
183 /**
184  * Message we send to the other peer to notify it that we intentionally
185  * are disconnecting (to reduce timeouts).  This is just a friendly
186  * notification, peers must not rely on always receiving disconnect
187  * messages.
188  */
189 struct GNUNET_ATS_SessionDisconnectMessage
190 {
191   /**
192    * Header of type #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT
193    */
194   struct GNUNET_MessageHeader header;
195
196   /**
197    * Always zero.
198    */
199   uint32_t reserved GNUNET_PACKED;
200
201   /**
202    * Purpose of the signature.  Extends over the timestamp.
203    * Purpose should be #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DISCONNECT.
204    */
205   struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
206
207   /**
208    * Absolute time at the sender.  Only the most recent connect
209    * message implies which session is preferred by the sender.
210    */
211   struct GNUNET_TIME_AbsoluteNBO timestamp;
212
213   /**
214    * Public key of the sender.
215    */
216   struct GNUNET_CRYPTO_EddsaPublicKey public_key;
217
218   /**
219    * Signature of the peer that sends us the disconnect.  Only
220    * valid if the timestamp is AFTER the timestamp from the
221    * corresponding 'SYN' message.
222    */
223   struct GNUNET_CRYPTO_EddsaSignature signature;
224
225 };
226
227 GNUNET_NETWORK_STRUCT_END
228
229
230 /**
231  * For each neighbour we keep a list of messages
232  * that we still want to transmit to the neighbour.
233  */
234 struct MessageQueue
235 {
236
237   /**
238    * This is a doubly linked list.
239    */
240   struct MessageQueue *next;
241
242   /**
243    * This is a doubly linked list.
244    */
245   struct MessageQueue *prev;
246
247   /**
248    * Function to call once we're done.
249    */
250   GST_NeighbourSendContinuation cont;
251
252   /**
253    * Closure for @e cont
254    */
255   void *cont_cls;
256
257   /**
258    * The message(s) we want to transmit, GNUNET_MessageHeader(s)
259    * stuck together in memory.  Allocated at the end of this struct.
260    */
261   const char *message_buf;
262
263   /**
264    * Size of the message buf
265    */
266   size_t message_buf_size;
267
268   /**
269    * At what time should we fail?
270    */
271   struct GNUNET_TIME_Absolute timeout;
272
273 };
274
275
276 /**
277  * A possible address we could use to communicate with a neighbour.
278  */
279 struct NeighbourAddress
280 {
281
282   /**
283    * Active session for this address.
284    */
285   struct GNUNET_ATS_Session *session;
286
287   /**
288    * Network-level address information.
289    */
290   struct GNUNET_HELLO_Address *address;
291
292   /**
293    * Timestamp of the 'SESSION_CONNECT' message we sent to the other
294    * peer for this address.  Use to check that the ACK is in response
295    * to our most recent 'SYN'.
296    */
297   struct GNUNET_TIME_Absolute connect_timestamp;
298
299   /**
300    * Inbound bandwidth from ATS for this address.
301    */
302   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
303
304   /**
305    * Outbound bandwidth from ATS for this address.
306    */
307   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
308
309   /**
310    * Did we tell ATS that this is our 'active' address?
311    */
312   int ats_active;
313
314   /**
315    * The current nonce sent in the last keep alive messages
316    */
317   uint32_t keep_alive_nonce;
318 };
319
320
321 /**
322  * Entry in neighbours.
323  */
324 struct NeighbourMapEntry
325 {
326
327   /**
328    * Head of list of messages we would like to send to this peer;
329    * must contain at most one message per client.
330    */
331   struct MessageQueue *messages_head;
332
333   /**
334    * Tail of list of messages we would like to send to this peer; must
335    * contain at most one message per client.
336    */
337   struct MessageQueue *messages_tail;
338
339   /**
340    * Are we currently trying to send a message? If so, which one?
341    */
342   struct MessageQueue *is_active;
343
344   /**
345    * Primary address we currently use to communicate with the neighbour.
346    */
347   struct NeighbourAddress primary_address;
348
349   /**
350    * Alternative address currently under consideration for communicating
351    * with the neighbour.
352    */
353   struct NeighbourAddress alternative_address;
354
355   /**
356    * Identity of this neighbour.
357    */
358   struct GNUNET_PeerIdentity id;
359
360   /**
361    * Main task that drives this peer (timeouts, keepalives, etc.).
362    * Always runs the #master_task().
363    */
364   struct GNUNET_SCHEDULER_Task *task;
365
366   /**
367    * Task to disconnect neighbour after we received a DISCONNECT message
368    */
369   struct GNUNET_SCHEDULER_Task *delayed_disconnect_task;
370
371   /**
372    * At what time should we sent the next keep-alive message?
373    */
374   struct GNUNET_TIME_Absolute keep_alive_time;
375
376   /**
377    * At what time did we sent the last keep-alive message?  Used
378    * to calculate round-trip time ("latency").
379    */
380   struct GNUNET_TIME_Absolute last_keep_alive_time;
381
382   /**
383    * Timestamp we should include in our next SYN_ACK message.
384    * (only valid if 'send_connect_ack' is #GNUNET_YES).  Used to build
385    * our SYN_ACK message.
386    */
387   struct GNUNET_TIME_Absolute connect_ack_timestamp;
388
389   /**
390    * ATS address suggest handle
391    */
392   struct GNUNET_ATS_ConnectivitySuggestHandle *suggest_handle;
393
394   /**
395    * Time where we should cut the connection (timeout) if we don't
396    * make progress in the state machine (or get a KEEPALIVE_RESPONSE
397    * if we are in #GNUNET_TRANSPORT_PS_CONNECTED).
398    */
399   struct GNUNET_TIME_Absolute timeout;
400
401   /**
402    * Tracker for inbound bandwidth.
403    */
404   struct GNUNET_BANDWIDTH_Tracker in_tracker;
405
406   /**
407    * How often has the other peer (recently) violated the inbound
408    * traffic limit?  Incremented by 10 per violation, decremented by 1
409    * per non-violation (for each time interval).
410    */
411   unsigned int quota_violation_count;
412
413   /**
414    * Latest quota the other peer send us in bytes per second.
415    * We should not send more, least the other peer throttle
416    * receiving our traffic.
417    */
418   struct GNUNET_BANDWIDTH_Value32NBO neighbour_receive_quota;
419
420   /**
421    * The current state of the peer.
422    */
423   enum GNUNET_TRANSPORT_PeerState state;
424
425   /**
426    * Did we sent an KEEP_ALIVE message and are we expecting a response?
427    */
428   int expect_latency_response;
429
430   /**
431    * When a peer wants to connect we have to reply to the 1st SYN message
432    * with a SYN_ACK message. But sometime we cannot send this message
433    * immediately since we do not have an address and then we have to remember
434    * to send this message as soon as we have an address.
435    *
436    * Flag to set if we still need to send a SYN_ACK message to the other peer
437    * (once we have an address to use and the peer has been allowed by our
438    * blacklist).  Initially set to #ACK_UNDEFINED. Set to #ACK_SEND_SYN_ACK
439    * if we need to send a SYN_ACK.  Set to #ACK_SEND_ACK if we did
440    * send a SYN_ACK and should go to #S_CONNECTED upon receiving a
441    * 'ACK' (regardless of what our own state machine might say).
442    */
443   enum GST_ACK_State ack_state;
444
445   /**
446    * Tracking utilization of outbound bandwidth
447    */
448   uint32_t util_total_bytes_sent;
449
450   /**
451    * Tracking utilization of inbound bandwidth
452    */
453   uint32_t util_total_bytes_recv;
454
455   /**
456    * Date of last utilization transmission
457    */
458   struct GNUNET_TIME_Absolute last_util_transmission;
459 };
460
461
462 /**
463  * Hash map from peer identities to the respective `struct NeighbourMapEntry`.
464  */
465 static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
466
467 /**
468  * List of pending blacklist checks: head
469  */
470 static struct BlacklistCheckSwitchContext *pending_bc_head;
471
472 /**
473  * List of pending blacklist checks: tail
474  */
475 static struct BlacklistCheckSwitchContext *pending_bc_tail;
476
477 /**
478  * counter for connected neighbours
479  */
480 static unsigned int neighbours_connected;
481
482 /**
483  * Number of bytes we have currently queued for transmission.
484  */
485 static unsigned long long bytes_in_send_queue;
486
487 /**
488  * Task transmitting utilization data
489  */
490 static struct GNUNET_SCHEDULER_Task *util_transmission_tk;
491
492
493 /**
494  * Convert the given ACK state to a string.
495  *
496  * @param s state
497  * @return corresponding human-readable string
498  */
499 static char *
500 print_ack_state (enum GST_ACK_State s)
501 {
502   switch (s) {
503     case ACK_UNDEFINED:
504       return "UNDEFINED";
505     case ACK_SEND_SYN_ACK:
506       return "SEND_SYN_ACK";
507     case ACK_SEND_ACK:
508       return "SEND_ACK";
509     default:
510       GNUNET_break (0);
511       return "N/A";
512   }
513 }
514
515
516 /**
517  * Send information about a new outbound quota to our clients.
518  * Note that the outbound quota is enforced client-side (i.e.
519  * in libgnunettransport).
520  *
521  * @param n affected peer
522  */
523 static void
524 send_outbound_quota_to_clients (struct NeighbourMapEntry *n)
525 {
526   struct QuotaSetMessage q_msg;
527   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_min;
528
529   if (! GNUNET_TRANSPORT_is_connected (n->state))
530     return;
531 #if IGNORE_INBOUND_QUOTA
532   bandwidth_min = n->primary_address.bandwidth_out;
533 #else
534   bandwidth_min = GNUNET_BANDWIDTH_value_min (n->primary_address.bandwidth_out,
535                                               n->neighbour_receive_quota);
536 #endif
537
538   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
539               "Sending outbound quota of %u Bps for peer `%s' to all clients\n",
540               ntohl (bandwidth_min.value__),
541               GNUNET_i2s (&n->id));
542   q_msg.header.size = htons (sizeof (struct QuotaSetMessage));
543   q_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA);
544   q_msg.quota = bandwidth_min;
545   q_msg.peer = n->id;
546   GST_clients_broadcast (&q_msg.header,
547                          GNUNET_NO);
548 }
549
550
551 /**
552  * Notify our clients that another peer connected to us.
553  *
554  * @param n the peer that connected
555  */
556 static void
557 neighbours_connect_notification (struct NeighbourMapEntry *n)
558 {
559   size_t len = sizeof(struct ConnectInfoMessage);
560   char buf[len] GNUNET_ALIGN;
561   struct ConnectInfoMessage *connect_msg = (struct ConnectInfoMessage *) buf;
562   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_min;
563
564 #if IGNORE_INBOUND_QUOTA
565   bandwidth_min = n->primary_address.bandwidth_out;
566 #else
567   bandwidth_min = GNUNET_BANDWIDTH_value_min (n->primary_address.bandwidth_out,
568                                               n->neighbour_receive_quota);
569 #endif
570   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
571               "We are now connected to peer `%s'\n",
572               GNUNET_i2s (&n->id));
573   connect_msg->header.size = htons (sizeof(buf));
574   connect_msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
575   connect_msg->id = n->id;
576   connect_msg->quota_out = bandwidth_min;
577   GST_clients_broadcast (&connect_msg->header,
578                          GNUNET_NO);
579 }
580
581
582 /**
583  * Notify our clients (and manipulation) that a peer disconnected from
584  * us.
585  *
586  * @param n the peer that disconnected
587  */
588 static void
589 neighbours_disconnect_notification (struct NeighbourMapEntry *n)
590 {
591   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
592               "Peer `%s' disconnected\n",
593               GNUNET_i2s (&n->id));
594   GST_manipulation_peer_disconnect (&n->id);
595   GST_clients_broadcast_disconnect (&n->id);
596 }
597
598
599 /**
600  * Notify transport clients that a neighbour peer changed its active
601  * address.
602  *
603  * @param peer identity of the peer
604  * @param address address possibly NULL if peer is not connected
605  * @param state current state this peer is in
606  * @param state_timeout timeout for the current state of the peer
607  * @param bandwidth_in bandwidth assigned inbound, 0 on disconnect
608  * @param bandwidth_out bandwidth assigned outbound, 0 on disconnect
609  */
610 static void
611 neighbours_changed_notification (const struct GNUNET_PeerIdentity *peer,
612                                  const struct GNUNET_HELLO_Address *address,
613                                  enum GNUNET_TRANSPORT_PeerState state,
614                                  struct GNUNET_TIME_Absolute state_timeout,
615                                  struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
616                                  struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
617 {
618   (void) bandwidth_in;
619   (void) bandwidth_out;
620   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
621               "Notifying about change for peer `%s' with address `%s' in state `%s' timing out at %s\n",
622               GNUNET_i2s (peer),
623               GST_plugins_a2s (address),
624               GNUNET_TRANSPORT_ps2s (state),
625               GNUNET_STRINGS_absolute_time_to_string (state_timeout));
626   /* FIXME: include bandwidth in notification! */
627   GST_clients_broadcast_peer_notification (peer,
628                                            address,
629                                            state,
630                                            state_timeout);
631 }
632
633
634 /**
635  * Lookup a neighbour entry in the neighbours hash map.
636  *
637  * @param pid identity of the peer to look up
638  * @return the entry, NULL if there is no existing record
639  */
640 static struct NeighbourMapEntry *
641 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
642 {
643   if (NULL == neighbours)
644     return NULL;
645   return GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
646 }
647
648
649 /**
650  * Test if we're connected to the given peer.
651  *
652  * @param n neighbour entry of peer to test
653  * @return #GNUNET_YES if we are connected, #GNUNET_NO if not
654  */
655 static int
656 test_connected (struct NeighbourMapEntry *n)
657 {
658   if (NULL == n)
659     return GNUNET_NO;
660   return GNUNET_TRANSPORT_is_connected (n->state);
661 }
662
663
664 /**
665  * We don't need a given neighbour address any more.
666  * Release its resources and give appropriate notifications
667  * to ATS and other subsystems.
668  *
669  * @param na address we are done with; @a na itself must NOT be 'free'd, only the contents!
670  */
671 static void
672 free_address (struct NeighbourAddress *na)
673 {
674   if (GNUNET_YES == na->ats_active)
675     GST_validation_set_address_use (na->address,
676                                     GNUNET_NO);
677   if (NULL != na->address)
678   {
679     GST_ats_block_address (na->address,
680                            na->session);
681     GNUNET_HELLO_address_free (na->address);
682     na->address = NULL;
683   }
684   na->bandwidth_in = GNUNET_BANDWIDTH_value_init (0);
685   na->bandwidth_out = GNUNET_BANDWIDTH_value_init (0);
686   na->ats_active = GNUNET_NO;
687   na->keep_alive_nonce = 0;
688   na->session = NULL;
689 }
690
691
692 /**
693  * Master task run for every neighbour.  Performs all of the time-related
694  * activities (keep alive, send next message, disconnect if idle, finish
695  * clean up after disconnect).
696  *
697  * @param cls the `struct NeighbourMapEntry` for which we are running
698  */
699 static void
700 master_task (void *cls);
701
702
703 /**
704  * Set net state and state timeout for this neighbour and notify monitoring
705  *
706  * @param n the respective neighbour
707  * @param s the new state
708  * @param timeout the new timeout
709  */
710 static void
711 set_state_and_timeout (struct NeighbourMapEntry *n,
712                        enum GNUNET_TRANSPORT_PeerState s,
713                        struct GNUNET_TIME_Absolute timeout)
714 {
715   if (GNUNET_TRANSPORT_is_connected (s) &&
716       ! GNUNET_TRANSPORT_is_connected (n->state) )
717   {
718     neighbours_connect_notification (n);
719     GNUNET_STATISTICS_set (GST_stats,
720                            gettext_noop ("# peers connected"),
721                            ++neighbours_connected,
722                            GNUNET_NO);
723   }
724   if (! GNUNET_TRANSPORT_is_connected (s) &&
725         GNUNET_TRANSPORT_is_connected (n->state) )
726   {
727     GNUNET_STATISTICS_set (GST_stats,
728                            gettext_noop ("# peers connected"),
729                            --neighbours_connected,
730                            GNUNET_NO);
731     neighbours_disconnect_notification (n);
732   }
733   n->state = s;
734   if ( (timeout.abs_value_us < n->timeout.abs_value_us) &&
735        (NULL != n->task ) )
736   {
737     /* new timeout is earlier, reschedule master task */
738     GNUNET_SCHEDULER_cancel (n->task);
739     n->task = GNUNET_SCHEDULER_add_at (timeout,
740                                        &master_task,
741                                        n);
742   }
743   n->timeout = timeout;
744   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
745               "Neighbour `%s' changed state to %s with timeout %s\n",
746               GNUNET_i2s (&n->id),
747               GNUNET_TRANSPORT_ps2s(s),
748               GNUNET_STRINGS_absolute_time_to_string (timeout));
749   neighbours_changed_notification (&n->id,
750                                    n->primary_address.address,
751                                    n->state,
752                                    n->timeout,
753                                    n->primary_address.bandwidth_in,
754                                    n->primary_address.bandwidth_out);
755 }
756
757
758 /**
759  * Initialize the alternative address of a neighbour
760  *
761  * @param n the neighbour
762  * @param address address of the other peer, NULL if other peer
763  *                       connected to us
764  * @param session session to use (or NULL, in which case an
765  *        address must be setup)
766  * @param bandwidth_in inbound quota to be used when connection is up
767  * @param bandwidth_out outbound quota to be used when connection is up
768  */
769 static void
770 set_alternative_address (struct NeighbourMapEntry *n,
771                          const struct GNUNET_HELLO_Address *address,
772                          struct GNUNET_ATS_Session *session,
773                          struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
774                          struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
775 {
776   struct GNUNET_TRANSPORT_PluginFunctions *papi;
777
778   if (NULL == (papi = GST_plugins_find (address->transport_name)))
779   {
780     GNUNET_break (0);
781     return;
782   }
783   if (session == n->alternative_address.session)
784   {
785     n->alternative_address.bandwidth_in = bandwidth_in;
786     n->alternative_address.bandwidth_out = bandwidth_out;
787     return;
788   }
789   if (NULL != n->alternative_address.address)
790   {
791     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
792                 "Replacing existing alternative address with another one\n");
793     free_address (&n->alternative_address);
794   }
795   if (NULL == session)
796     session = papi->get_session (papi->cls,
797                                  address);
798   if (NULL == session)
799   {
800     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
801                 "Failed to obtain new session for peer `%s' and  address '%s'\n",
802                 GNUNET_i2s (&address->peer),
803                 GST_plugins_a2s (address));
804     GNUNET_STATISTICS_update (GST_stats,
805                               gettext_noop ("# session creation failed"),
806                               1,
807                               GNUNET_NO);
808     return;
809   }
810   GST_ats_new_session (address,
811                        session);
812   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
813               "Neighbour `%s' configured alternative address %s\n",
814               GNUNET_i2s (&n->id),
815               GST_plugins_a2s(address));
816
817   n->alternative_address.address = GNUNET_HELLO_address_copy (address);
818   n->alternative_address.bandwidth_in = bandwidth_in;
819   n->alternative_address.bandwidth_out = bandwidth_out;
820   n->alternative_address.session = session;
821   n->alternative_address.ats_active = GNUNET_NO;
822   n->alternative_address.keep_alive_nonce = 0;
823   GNUNET_assert (GNUNET_YES ==
824                  GST_ats_is_known (n->alternative_address.address,
825                                    n->alternative_address.session));
826 }
827
828
829 /**
830  * Transmit a message using the current session of the given
831  * neighbour.
832  *
833  * @param n entry for the recipient
834  * @param msgbuf buffer to transmit
835  * @param msgbuf_size number of bytes in @a msgbuf buffer
836  * @param priority transmission priority
837  * @param timeout transmission timeout
838  * @param use_keepalive_timeout #GNUNET_YES to use plugin-specific keep-alive
839  *        timeout (@a timeout is ignored in that case), #GNUNET_NO otherwise
840  * @param cont continuation to call when finished (can be NULL)
841  * @param cont_cls closure for @a cont
842  * @return timeout (copy of @a timeout or a calculated one if
843  *         @a use_keepalive_timeout is #GNUNET_YES.
844  */
845 static struct GNUNET_TIME_Relative
846 send_with_session (struct NeighbourMapEntry *n,
847                    const void *msgbuf,
848                    size_t msgbuf_size,
849                    uint32_t priority,
850                    struct GNUNET_TIME_Relative timeout,
851                    unsigned int use_keepalive_timeout,
852                    GNUNET_TRANSPORT_TransmitContinuation cont,
853                    void *cont_cls)
854 {
855   struct GNUNET_TRANSPORT_PluginFunctions *papi;
856   struct GNUNET_TIME_Relative result = GNUNET_TIME_UNIT_FOREVER_REL;
857
858   GNUNET_assert (NULL != n->primary_address.session);
859   if ( ((NULL == (papi = GST_plugins_find (n->primary_address.address->transport_name)) ||
860          (-1 == papi->send (papi->cls,
861                             n->primary_address.session,
862                             msgbuf,
863                             msgbuf_size,
864                             priority,
865                             (result = (GNUNET_NO == use_keepalive_timeout) ? timeout :
866                              GNUNET_TIME_relative_divide (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
867                                                           papi->query_keepalive_factor (papi->cls))),
868                             cont,
869                             cont_cls)))) &&
870        (NULL != cont))
871     cont (cont_cls,
872           &n->id,
873           GNUNET_SYSERR,
874           msgbuf_size,
875           0);
876   GST_neighbours_notify_data_sent (n->primary_address.address,
877                                    n->primary_address.session,
878                                    msgbuf_size);
879   GNUNET_break (NULL != papi);
880   return result;
881 }
882
883
884 /**
885  * Clear the primary address of a neighbour since this address is not
886  * valid anymore and notify monitoring about it
887  *
888  * @param n the neighbour
889  */
890 static void
891 unset_primary_address (struct NeighbourMapEntry *n)
892 {
893   /* Notify monitoring about change */
894   if (NULL == n->primary_address.address)
895     return;
896   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
897               "Disabling primary address\n");
898   neighbours_changed_notification (&n->id,
899                                    n->primary_address.address,
900                                    n->state,
901                                    n->timeout,
902                                    GNUNET_BANDWIDTH_value_init (0),
903                                    GNUNET_BANDWIDTH_value_init (0));
904   free_address (&n->primary_address);
905 }
906
907
908 /**
909  * Free a neighbour map entry.
910  *
911  * @param n entry to free
912  */
913 static void
914 free_neighbour (struct NeighbourMapEntry *n)
915 {
916   struct MessageQueue *mq;
917
918   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
919               "Freeing neighbour state of peer `%s'\n",
920               GNUNET_i2s (&n->id));
921   n->is_active = NULL; /* always free'd by its own continuation! */
922
923   /* fail messages currently in the queue */
924   while (NULL != (mq = n->messages_head))
925   {
926     GNUNET_CONTAINER_DLL_remove (n->messages_head,
927                                  n->messages_tail,
928                                  mq);
929     if (NULL != mq->cont)
930       mq->cont (mq->cont_cls,
931                 GNUNET_SYSERR,
932                 mq->message_buf_size,
933                 0);
934     GNUNET_free (mq);
935   }
936   /* Mark peer as disconnected */
937   set_state_and_timeout (n,
938                          GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED,
939                          GNUNET_TIME_UNIT_FOREVER_ABS);
940   /* free addresses and mark as unused */
941   unset_primary_address (n);
942
943   if (NULL != n->alternative_address.address)
944   {
945     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
946                 "Cleaning up alternative address\n");
947     free_address (&n->alternative_address);
948   }
949   GNUNET_assert (GNUNET_YES ==
950                  GNUNET_CONTAINER_multipeermap_remove (neighbours,
951                                                        &n->id, n));
952
953   /* Cancel address requests for this peer */
954   if (NULL != n->suggest_handle)
955   {
956     GNUNET_ATS_connectivity_suggest_cancel (n->suggest_handle);
957     n->suggest_handle = NULL;
958   }
959
960   /* Cancel the disconnect task */
961   if (NULL != n->delayed_disconnect_task)
962   {
963     GNUNET_SCHEDULER_cancel (n->delayed_disconnect_task);
964     n->delayed_disconnect_task = NULL;
965   }
966
967   /* Cancel the master task */
968   if (NULL != n->task)
969   {
970     GNUNET_SCHEDULER_cancel (n->task);
971     n->task = NULL;
972   }
973   /* free rest of memory */
974   GNUNET_free (n);
975 }
976
977
978 /**
979  * Function called when the 'DISCONNECT' message has been sent by the
980  * plugin.  Frees the neighbour --- if the entry still exists.
981  *
982  * @param cls NULL
983  * @param target identity of the neighbour that was disconnected
984  * @param result #GNUNET_OK if the disconnect got out successfully
985  * @param payload bytes payload
986  * @param physical bytes on wire
987  */
988 static void
989 send_disconnect_cont (void *cls,
990                       const struct GNUNET_PeerIdentity *target,
991                       int result,
992                       size_t payload,
993                       size_t physical)
994 {
995   struct NeighbourMapEntry *n;
996
997   (void) cls;
998   (void) result;
999   (void) payload;
1000   (void) physical;
1001   n = lookup_neighbour (target);
1002   if (NULL == n)
1003     return; /* already gone */
1004   if (GNUNET_TRANSPORT_PS_DISCONNECT != n->state)
1005     return; /* have created a fresh entry since */
1006   if (NULL != n->task)
1007     GNUNET_SCHEDULER_cancel (n->task);
1008   n->task = GNUNET_SCHEDULER_add_now (&master_task, n);
1009 }
1010
1011
1012 /**
1013  * Transmit a DISCONNECT message to the other peer.
1014  *
1015  * @param n neighbour to send DISCONNECT message.
1016  */
1017 static void
1018 send_disconnect (struct NeighbourMapEntry *n)
1019 {
1020   struct GNUNET_ATS_SessionDisconnectMessage disconnect_msg;
1021
1022   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1023               "Sending DISCONNECT message to peer `%4s'\n",
1024               GNUNET_i2s (&n->id));
1025   disconnect_msg.header.size = htons (sizeof (struct GNUNET_ATS_SessionDisconnectMessage));
1026   disconnect_msg.header.type =
1027       htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT);
1028   disconnect_msg.reserved = htonl (0);
1029   disconnect_msg.purpose.size =
1030       htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
1031              sizeof (struct GNUNET_CRYPTO_EddsaPublicKey) +
1032              sizeof (struct GNUNET_TIME_AbsoluteNBO));
1033   disconnect_msg.purpose.purpose =
1034       htonl (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT);
1035   disconnect_msg.timestamp =
1036       GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
1037   disconnect_msg.public_key = GST_my_identity.public_key;
1038   GNUNET_assert (GNUNET_OK ==
1039                  GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
1040                                          &disconnect_msg.purpose,
1041                                          &disconnect_msg.signature));
1042
1043   (void) send_with_session (n,
1044                             &disconnect_msg,
1045                             sizeof (disconnect_msg),
1046                             UINT32_MAX,
1047                             GNUNET_TIME_UNIT_FOREVER_REL,
1048                             GNUNET_NO,
1049                             &send_disconnect_cont,
1050                             NULL);
1051   GNUNET_STATISTICS_update (GST_stats,
1052                             gettext_noop ("# DISCONNECT messages sent"),
1053                             1,
1054                             GNUNET_NO);
1055 }
1056
1057
1058 /**
1059  * Disconnect from the given neighbour, clean up the record.
1060  *
1061  * @param n neighbour to disconnect from
1062  */
1063 static void
1064 disconnect_neighbour (struct NeighbourMapEntry *n)
1065 {
1066   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1067               "Disconnecting from peer %s in state %s\n",
1068               GNUNET_i2s (&n->id),
1069               GNUNET_TRANSPORT_ps2s (n->state));
1070   /* depending on state, notify neighbour and/or upper layers of this peer
1071      about disconnect */
1072   switch (n->state)
1073   {
1074   case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
1075   case GNUNET_TRANSPORT_PS_INIT_ATS:
1076     /* other peer is completely unaware of us, no need to send DISCONNECT */
1077     free_neighbour (n);
1078     return;
1079   case GNUNET_TRANSPORT_PS_SYN_SENT:
1080     send_disconnect (n);
1081     set_state_and_timeout (n,
1082                            GNUNET_TRANSPORT_PS_DISCONNECT,
1083                            GNUNET_TIME_UNIT_FOREVER_ABS);
1084     break;
1085   case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
1086     /* we never ACK'ed the other peer's request, no need to send DISCONNECT */
1087     free_neighbour (n);
1088     return;
1089   case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
1090     /* we DID ACK the other peer's request, must send DISCONNECT */
1091     send_disconnect (n);
1092     set_state_and_timeout (n,
1093                            GNUNET_TRANSPORT_PS_DISCONNECT,
1094                            GNUNET_TIME_UNIT_FOREVER_ABS);
1095     break;
1096   case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
1097   case GNUNET_TRANSPORT_PS_CONNECTED:
1098   case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
1099     /* we are currently connected, need to send disconnect and do
1100        internal notifications and update statistics */
1101     send_disconnect (n);
1102     set_state_and_timeout (n,
1103                            GNUNET_TRANSPORT_PS_DISCONNECT,
1104                            GNUNET_TIME_UNIT_FOREVER_ABS);
1105     break;
1106   case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
1107     /* Disconnecting while waiting for an ATS address to reconnect,
1108      * cannot send DISCONNECT */
1109     free_neighbour (n);
1110     return;
1111   case GNUNET_TRANSPORT_PS_DISCONNECT:
1112     /* already disconnected, ignore */
1113     break;
1114   case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
1115     /* already cleaned up, how did we get here!? */
1116     GNUNET_assert (0);
1117     break;
1118   default:
1119     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1120                 "Unhandled state `%s'\n",
1121                 GNUNET_TRANSPORT_ps2s (n->state));
1122     GNUNET_break (0);
1123     break;
1124   }
1125   /* schedule timeout to clean up */
1126   if (NULL != n->task)
1127     GNUNET_SCHEDULER_cancel (n->task);
1128   n->task = GNUNET_SCHEDULER_add_delayed (DISCONNECT_SENT_TIMEOUT,
1129                                           &master_task,
1130                                           n);
1131 }
1132
1133
1134 /**
1135  * Change the incoming quota for the given peer.  Updates
1136  * our own receive rate and informs the neighbour about
1137  * the new quota.
1138  *
1139  * @param n neighbour entry to change quota for
1140  * @param quota new quota
1141  * @return #GNUNET_YES if @a n is still valid, #GNUNET_NO if
1142  *   @a n was freed
1143  */
1144 static int
1145 set_incoming_quota (struct NeighbourMapEntry *n,
1146                     struct GNUNET_BANDWIDTH_Value32NBO quota)
1147 {
1148   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1149               "Setting inbound quota of %u Bps for peer `%s' to all clients\n",
1150               ntohl (quota.value__), GNUNET_i2s (&n->id));
1151   GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
1152                                          quota);
1153   if (0 != ntohl (quota.value__))
1154   {
1155     struct GNUNET_ATS_SessionQuotaMessage sqm;
1156
1157     sqm.header.size = htons (sizeof (struct GNUNET_ATS_SessionQuotaMessage));
1158     sqm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_QUOTA);
1159     sqm.quota = quota.value__;
1160     if (NULL != n->primary_address.session)
1161       (void) send_with_session (n,
1162                                 &sqm,
1163                                 sizeof (sqm),
1164                                 UINT32_MAX - 1,
1165                                 GNUNET_TIME_UNIT_FOREVER_REL,
1166                                 GNUNET_NO,
1167                                 NULL, NULL);
1168     return GNUNET_YES;
1169   }
1170   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1171               "Disconnecting peer `%s' due to SET_QUOTA\n",
1172               GNUNET_i2s (&n->id));
1173   if (GNUNET_YES == test_connected (n))
1174     GNUNET_STATISTICS_update (GST_stats,
1175                               gettext_noop ("# disconnects due to quota of 0"),
1176                               1, GNUNET_NO);
1177   disconnect_neighbour (n);
1178   return GNUNET_NO;
1179 }
1180
1181
1182 /**
1183  * Initialize the primary address of a neighbour
1184  *
1185  * @param n the neighbour
1186  * @param address address of the other peer, NULL if other peer
1187  *                       connected to us
1188  * @param session session to use (or NULL, in which case an
1189  *        address must be setup)
1190  * @param bandwidth_in inbound quota to be used when connection is up
1191  * @param bandwidth_out outbound quota to be used when connection is up
1192  */
1193 static void
1194 set_primary_address (struct NeighbourMapEntry *n,
1195                      const struct GNUNET_HELLO_Address *address,
1196                      struct GNUNET_ATS_Session *session,
1197                      struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
1198                      struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
1199 {
1200   if (session == n->primary_address.session)
1201   {
1202     GST_validation_set_address_use (n->primary_address.address,
1203                                     GNUNET_YES);
1204     if (n->primary_address.bandwidth_in.value__ != bandwidth_in.value__)
1205     {
1206       n->primary_address.bandwidth_in = bandwidth_in;
1207       if (GNUNET_YES !=
1208           set_incoming_quota (n,
1209                               bandwidth_in))
1210         return;
1211     }
1212     if (n->primary_address.bandwidth_out.value__ != bandwidth_out.value__)
1213     {
1214       n->primary_address.bandwidth_out = bandwidth_out;
1215       send_outbound_quota_to_clients (n);
1216     }
1217     return;
1218   }
1219   if ( (NULL != n->primary_address.address) &&
1220        (0 == GNUNET_HELLO_address_cmp (address,
1221                                        n->primary_address.address)) )
1222   {
1223     GNUNET_break (0);
1224     return;
1225   }
1226   if (NULL == session)
1227   {
1228     GNUNET_break (0);
1229     GST_ats_block_address (address,
1230                            session);
1231     return;
1232   }
1233   if (NULL != n->primary_address.address)
1234   {
1235     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1236                 "Replacing existing primary address with another one\n");
1237     free_address (&n->primary_address);
1238   }
1239   n->primary_address.address = GNUNET_HELLO_address_copy (address);
1240   n->primary_address.bandwidth_in = bandwidth_in;
1241   n->primary_address.bandwidth_out = bandwidth_out;
1242   n->primary_address.session = session;
1243   n->primary_address.keep_alive_nonce = 0;
1244   GNUNET_assert (GNUNET_YES ==
1245                  GST_ats_is_known (n->primary_address.address,
1246                                    n->primary_address.session));
1247   /* subsystems about address use */
1248   GST_validation_set_address_use (n->primary_address.address,
1249                                   GNUNET_YES);
1250   if (GNUNET_YES !=
1251       set_incoming_quota (n,
1252                           bandwidth_in))
1253     return;
1254   send_outbound_quota_to_clients (n);
1255   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1256               "Neighbour `%s' switched to address `%s'\n",
1257               GNUNET_i2s (&n->id),
1258               GST_plugins_a2s(address));
1259
1260   neighbours_changed_notification (&n->id,
1261                                    n->primary_address.address,
1262                                    n->state,
1263                                    n->timeout,
1264                                    n->primary_address.bandwidth_in,
1265                                    n->primary_address.bandwidth_out);
1266 }
1267
1268
1269 /**
1270  * We're done with our transmission attempt, continue processing.
1271  *
1272  * @param cls the `struct MessageQueue` of the message
1273  * @param receiver intended receiver
1274  * @param success whether it worked or not
1275  * @param size_payload bytes payload sent
1276  * @param physical bytes sent on wire
1277  */
1278 static void
1279 transmit_send_continuation (void *cls,
1280                             const struct GNUNET_PeerIdentity *receiver,
1281                             int success,
1282                             size_t size_payload,
1283                             size_t physical)
1284 {
1285   struct MessageQueue *mq = cls;
1286   struct NeighbourMapEntry *n;
1287
1288   if (NULL == (n = lookup_neighbour (receiver)))
1289   {
1290     if (NULL != mq->cont)
1291       mq->cont (mq->cont_cls,
1292                 GNUNET_SYSERR /* not connected */,
1293                 size_payload,
1294                 0);
1295     GNUNET_free (mq);
1296     return; /* disconnect or other error while transmitting, can happen */
1297   }
1298   if (n->is_active == mq)
1299   {
1300     /* this is still "our" neighbour, remove us from its queue
1301        and allow it to send the next message now */
1302     n->is_active = NULL;
1303     if (NULL != n->task)
1304       GNUNET_SCHEDULER_cancel (n->task);
1305     n->task = GNUNET_SCHEDULER_add_now (&master_task,
1306                                         n);
1307   }
1308   if (bytes_in_send_queue < mq->message_buf_size)
1309   {
1310     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1311                 "Bytes_in_send_queue `%llu', Message_size %u, result: %s, payload %u, on wire %u\n",
1312                 bytes_in_send_queue,
1313                 (unsigned int) mq->message_buf_size,
1314                 (GNUNET_OK == success) ? "OK" : "FAIL",
1315                 (unsigned int) size_payload,
1316                 (unsigned int) physical);
1317     GNUNET_break (0);
1318   }
1319
1320   GNUNET_break (size_payload == mq->message_buf_size);
1321   bytes_in_send_queue -= mq->message_buf_size;
1322   GNUNET_STATISTICS_set (GST_stats,
1323                          gettext_noop ("# bytes in message queue for other peers"),
1324                          bytes_in_send_queue,
1325                          GNUNET_NO);
1326   if (GNUNET_OK == success)
1327     GNUNET_STATISTICS_update (GST_stats,
1328                               gettext_noop ("# messages transmitted to other peers"),
1329                               1,
1330                               GNUNET_NO);
1331   else
1332     GNUNET_STATISTICS_update (GST_stats,
1333                               gettext_noop
1334                               ("# transmission failures for messages to other peers"),
1335                               1, GNUNET_NO);
1336   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1337               "Sending message to `%s' of type %u with %u bytes was a %s\n",
1338               GNUNET_i2s (receiver),
1339               ntohs (((struct GNUNET_MessageHeader *) mq->message_buf)->type),
1340               (unsigned int) mq->message_buf_size,
1341               (success == GNUNET_OK) ? "success" : "FAILURE");
1342   if (NULL != mq->cont)
1343     mq->cont (mq->cont_cls,
1344               success,
1345               size_payload,
1346               physical);
1347   GNUNET_free (mq);
1348 }
1349
1350
1351 /**
1352  * Check the message list for the given neighbour and if we can
1353  * send a message, do so.  This function should only be called
1354  * if the connection is at least generally ready for transmission.
1355  * While we will only send one message at a time, no bandwidth
1356  * quota management is performed here.  If a message was given to
1357  * the plugin, the continuation will automatically re-schedule
1358  * the 'master' task once the next message might be transmitted.
1359  *
1360  * @param n target peer for which to transmit
1361  */
1362 static void
1363 try_transmission_to_peer (struct NeighbourMapEntry *n)
1364 {
1365   struct MessageQueue *mq;
1366   struct GNUNET_TIME_Relative timeout;
1367
1368   if (NULL == n->primary_address.address)
1369   {
1370     /* no address, why are we here? */
1371     GNUNET_break (0);
1372     return;
1373   }
1374   if ((0 == n->primary_address.address->address_length) &&
1375       (NULL == n->primary_address.session))
1376   {
1377     /* no address, why are we here? */
1378     GNUNET_break (0);
1379     return;
1380   }
1381   if (NULL != n->is_active)
1382   {
1383     /* transmission already pending */
1384     return;
1385   }
1386
1387   /* timeout messages from the queue that are past their due date */
1388   while (NULL != (mq = n->messages_head))
1389   {
1390     timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1391     if (timeout.rel_value_us > 0)
1392       break;
1393     GNUNET_STATISTICS_update (GST_stats,
1394                               gettext_noop ("# messages timed out while in transport queue"),
1395                               1,
1396                               GNUNET_NO);
1397     GNUNET_CONTAINER_DLL_remove (n->messages_head,
1398                                  n->messages_tail,
1399                                  mq);
1400     n->is_active = mq;
1401     transmit_send_continuation (mq,
1402                                 &n->id,
1403                                 GNUNET_SYSERR,
1404                                 mq->message_buf_size,
1405                                 0);     /* timeout */
1406   }
1407   if (NULL == mq)
1408     return;                     /* no more messages */
1409   if (NULL == n->primary_address.address)
1410   {
1411     /* transmit_send_continuation() caused us to drop session,
1412        can't try transmission anymore. */
1413     return;
1414   }
1415
1416
1417   GNUNET_CONTAINER_DLL_remove (n->messages_head,
1418                                n->messages_tail,
1419                                mq);
1420   n->is_active = mq;
1421
1422   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1423               "Giving message with %u bytes to plugin session %p\n",
1424               (unsigned int) mq->message_buf_size,
1425               n->primary_address.session);
1426   (void) send_with_session (n,
1427                             mq->message_buf,
1428                             mq->message_buf_size,
1429                             0 /* priority */,
1430                             timeout,
1431                             GNUNET_NO,
1432                             &transmit_send_continuation,
1433                             mq);
1434 }
1435
1436
1437 /**
1438  * Send keepalive message to the neighbour.  Must only be called
1439  * if we are on 'connected' state or while trying to switch addresses.
1440  * Will internally determine if a keepalive is truly needed (so can
1441  * always be called).
1442  *
1443  * @param n neighbour that went idle and needs a keepalive
1444  */
1445 static void
1446 send_keepalive (struct NeighbourMapEntry *n)
1447 {
1448   struct GNUNET_ATS_SessionKeepAliveMessage m;
1449   struct GNUNET_TIME_Relative timeout;
1450   uint32_t nonce;
1451
1452   GNUNET_assert ((GNUNET_TRANSPORT_PS_CONNECTED == n->state) ||
1453                  (GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT == n->state));
1454   if (GNUNET_TIME_absolute_get_remaining (n->keep_alive_time).rel_value_us > 0)
1455     return; /* no keepalive needed at this time */
1456
1457   nonce = 0; /* 0 indicates 'not set' */
1458   while (0 == nonce)
1459     nonce = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1460                                       UINT32_MAX);
1461
1462   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1463               "Sending KEEPALIVE to peer `%s' with nonce %u\n",
1464               GNUNET_i2s (&n->id),
1465               nonce);
1466   m.header.size = htons (sizeof (struct GNUNET_ATS_SessionKeepAliveMessage));
1467   m.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE);
1468   m.nonce = htonl (nonce);
1469
1470   timeout = send_with_session (n,
1471                                &m,
1472                                sizeof (m),
1473                                UINT32_MAX /* priority */,
1474                                GNUNET_TIME_UNIT_FOREVER_REL,
1475                                GNUNET_YES,
1476                                NULL, NULL);
1477   GNUNET_STATISTICS_update (GST_stats,
1478                             gettext_noop ("# KEEPALIVES sent"),
1479                             1,
1480                             GNUNET_NO);
1481   n->primary_address.keep_alive_nonce = nonce;
1482   n->expect_latency_response = GNUNET_YES;
1483   n->last_keep_alive_time = GNUNET_TIME_absolute_get ();
1484   n->keep_alive_time = GNUNET_TIME_relative_to_absolute (timeout);
1485 }
1486
1487
1488 /**
1489  * Keep the connection to the given neighbour alive longer,
1490  * we received a KEEPALIVE (or equivalent); send a response.
1491  *
1492  * @param neighbour neighbour to keep alive (by sending keep alive response)
1493  * @param m the keep alive message containing the nonce to respond to
1494  */
1495 void
1496 GST_neighbours_keepalive (const struct GNUNET_PeerIdentity *neighbour,
1497                           const struct GNUNET_MessageHeader *m)
1498 {
1499   struct NeighbourMapEntry *n;
1500   const struct GNUNET_ATS_SessionKeepAliveMessage *msg_in;
1501   struct GNUNET_ATS_SessionKeepAliveMessage msg;
1502
1503   if (sizeof (struct GNUNET_ATS_SessionKeepAliveMessage) != ntohs (m->size))
1504   {
1505     GNUNET_break_op (0);
1506     return;
1507   }
1508
1509   msg_in = (const struct GNUNET_ATS_SessionKeepAliveMessage *) m;
1510   if (NULL == (n = lookup_neighbour (neighbour)))
1511   {
1512     GNUNET_STATISTICS_update (GST_stats,
1513                               gettext_noop
1514                               ("# KEEPALIVE messages discarded (peer unknown)"),
1515                               1, GNUNET_NO);
1516     return;
1517   }
1518   if (NULL == n->primary_address.session)
1519   {
1520     GNUNET_STATISTICS_update (GST_stats,
1521                               gettext_noop
1522                               ("# KEEPALIVE messages discarded (no session)"),
1523                               1, GNUNET_NO);
1524     return;
1525   }
1526
1527   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1528               "Received KEEPALIVE request from peer `%s' with nonce %u\n",
1529               GNUNET_i2s (&n->id),
1530               ntohl (msg_in->nonce));
1531   GNUNET_STATISTICS_update (GST_stats,
1532                             gettext_noop ("# KEEPALIVES received in good order"),
1533                             1,
1534                             GNUNET_NO);
1535
1536   /* send reply to allow neighbour to measure latency */
1537   msg.header.size = htons (sizeof (struct GNUNET_ATS_SessionKeepAliveMessage));
1538   msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE_RESPONSE);
1539   msg.nonce = msg_in->nonce;
1540   (void) send_with_session (n,
1541                             &msg,
1542                             sizeof (struct GNUNET_ATS_SessionKeepAliveMessage),
1543                             UINT32_MAX /* priority */,
1544                             GNUNET_TIME_UNIT_FOREVER_REL,
1545                             GNUNET_YES,
1546                             NULL, NULL);
1547 }
1548
1549
1550 /**
1551  * We received a KEEP_ALIVE_RESPONSE message and use this to calculate
1552  * latency to this peer.  Pass the updated information (existing ats
1553  * plus calculated latency) to ATS.
1554  *
1555  * @param neighbour neighbour to keep alive
1556  * @param m the message containing the keep alive response
1557  */
1558 void
1559 GST_neighbours_keepalive_response (const struct GNUNET_PeerIdentity *neighbour,
1560                                    const struct GNUNET_MessageHeader *m)
1561 {
1562   struct NeighbourMapEntry *n;
1563   const struct GNUNET_ATS_SessionKeepAliveMessage *msg;
1564   struct GNUNET_TRANSPORT_PluginFunctions *papi;
1565   struct GNUNET_TIME_Relative latency;
1566
1567   if (sizeof (struct GNUNET_ATS_SessionKeepAliveMessage) != ntohs (m->size))
1568   {
1569     GNUNET_break_op (0);
1570     return;
1571   }
1572
1573   msg = (const struct GNUNET_ATS_SessionKeepAliveMessage *) m;
1574   if (NULL == (n = lookup_neighbour (neighbour)))
1575   {
1576     GNUNET_STATISTICS_update (GST_stats,
1577                               gettext_noop ("# KEEPALIVE_RESPONSEs discarded (not connected)"),
1578                               1,
1579                               GNUNET_NO);
1580     return;
1581   }
1582   if ( (GNUNET_TRANSPORT_PS_CONNECTED != n->state) ||
1583        (GNUNET_YES != n->expect_latency_response) )
1584   {
1585     GNUNET_STATISTICS_update (GST_stats,
1586                               gettext_noop ("# KEEPALIVE_RESPONSEs discarded (not expected)"),
1587                               1,
1588                               GNUNET_NO);
1589     return;
1590   }
1591   if (NULL == n->primary_address.address)
1592   {
1593     GNUNET_STATISTICS_update (GST_stats,
1594                               gettext_noop ("# KEEPALIVE_RESPONSEs discarded (address changed)"),
1595                               1,
1596                               GNUNET_NO);
1597     return;
1598   }
1599   if (n->primary_address.keep_alive_nonce != ntohl (msg->nonce))
1600   {
1601     if (0 == n->primary_address.keep_alive_nonce)
1602       GNUNET_STATISTICS_update (GST_stats,
1603                                 gettext_noop ("# KEEPALIVE_RESPONSEs discarded (no nonce)"),
1604                                 1,
1605                                 GNUNET_NO);
1606     else
1607       GNUNET_STATISTICS_update (GST_stats,
1608                                 gettext_noop ("# KEEPALIVE_RESPONSEs discarded (bad nonce)"),
1609                                 1,
1610                                 GNUNET_NO);
1611     return;
1612   }
1613   GNUNET_STATISTICS_update (GST_stats,
1614                             gettext_noop ("# KEEPALIVE_RESPONSEs received (OK)"),
1615                             1,
1616                             GNUNET_NO);
1617
1618
1619   /* Update session timeout here */
1620   if (NULL != (papi = GST_plugins_find (n->primary_address.address->transport_name)))
1621   {
1622     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1623                 "Updating session for peer `%s' for session %p\n",
1624                 GNUNET_i2s (&n->id),
1625                 n->primary_address.session);
1626     papi->update_session_timeout (papi->cls,
1627                                   &n->id,
1628                                   n->primary_address.session);
1629   }
1630   else
1631   {
1632     GNUNET_break (0);
1633   }
1634
1635   n->primary_address.keep_alive_nonce = 0;
1636   n->expect_latency_response = GNUNET_NO;
1637   set_state_and_timeout (n,
1638                          n->state,
1639                          GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT));
1640
1641   latency = GNUNET_TIME_absolute_get_duration (n->last_keep_alive_time);
1642   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1643               "Received KEEPALIVE_RESPONSE from peer `%s', latency is %s\n",
1644               GNUNET_i2s (&n->id),
1645               GNUNET_STRINGS_relative_time_to_string (latency,
1646                                                       GNUNET_YES));
1647   GST_ats_update_delay (n->primary_address.address,
1648                         GNUNET_TIME_relative_divide (latency,
1649                                                      2));
1650 }
1651
1652
1653 /**
1654  * We have received a message from the given sender.  How long should
1655  * we delay before receiving more?  (Also used to keep the peer marked
1656  * as live).
1657  *
1658  * @param sender sender of the message
1659  * @param size size of the message
1660  * @param do_forward set to #GNUNET_YES if the message should be forwarded to clients
1661  *                   #GNUNET_NO if the neighbour is not connected or violates the quota,
1662  *                   #GNUNET_SYSERR if the connection is not fully up yet
1663  * @return how long to wait before reading more from this sender
1664  */
1665 struct GNUNET_TIME_Relative
1666 GST_neighbours_calculate_receive_delay (const struct GNUNET_PeerIdentity *sender,
1667                                         ssize_t size,
1668                                         int *do_forward)
1669 {
1670   struct NeighbourMapEntry *n;
1671   struct GNUNET_TIME_Relative ret;
1672
1673   if (NULL == neighbours)
1674   {
1675     *do_forward = GNUNET_NO;
1676     return GNUNET_TIME_UNIT_FOREVER_REL; /* This can happen during shutdown */
1677   }
1678   if (NULL == (n = lookup_neighbour (sender)))
1679   {
1680     GNUNET_STATISTICS_update (GST_stats,
1681                               gettext_noop ("# messages discarded due to lack of neighbour record"),
1682                               1,
1683                               GNUNET_NO);
1684     *do_forward = GNUNET_NO;
1685     return GNUNET_TIME_UNIT_ZERO;
1686   }
1687   if (! test_connected (n))
1688   {
1689     *do_forward = GNUNET_SYSERR;
1690     return GNUNET_TIME_UNIT_ZERO;
1691   }
1692   if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, size))
1693   {
1694     n->quota_violation_count++;
1695     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1696                 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
1697                 n->in_tracker.available_bytes_per_s__,
1698                 n->quota_violation_count);
1699     /* Discount 32k per violation */
1700     GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, -32 * 1024);
1701   }
1702   else
1703   {
1704     if (n->quota_violation_count > 0)
1705     {
1706       /* try to add 32k back */
1707       GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, 32 * 1024);
1708       n->quota_violation_count--;
1709     }
1710   }
1711   if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
1712   {
1713     GNUNET_STATISTICS_update (GST_stats,
1714                               gettext_noop
1715                               ("# bandwidth quota violations by other peers"),
1716                               1, GNUNET_NO);
1717     *do_forward = GNUNET_NO;
1718     return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
1719   }
1720   *do_forward = GNUNET_YES;
1721   ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 32 * 1024);
1722   if (ret.rel_value_us > 0)
1723   {
1724     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1725                 "Throttling read (%lld bytes excess at %u b/s), waiting %s before reading more.\n",
1726                 (long long) n->in_tracker.consumption_since_last_update__,
1727                 (unsigned int) n->in_tracker.available_bytes_per_s__,
1728                 GNUNET_STRINGS_relative_time_to_string (ret, GNUNET_YES));
1729     GNUNET_STATISTICS_update (GST_stats,
1730                               gettext_noop ("# ms throttling suggested"),
1731                               (int64_t) ret.rel_value_us / 1000LL,
1732                               GNUNET_NO);
1733   }
1734   return ret;
1735 }
1736
1737
1738 /**
1739  * Transmit a message to the given target using the active connection.
1740  *
1741  * @param target destination
1742  * @param msg message to send
1743  * @param msg_size number of bytes in msg
1744  * @param timeout when to fail with timeout
1745  * @param cont function to call when done
1746  * @param cont_cls closure for @a cont
1747  */
1748 void
1749 GST_neighbours_send (const struct GNUNET_PeerIdentity *target,
1750                      const void *msg,
1751                      size_t msg_size,
1752                      struct GNUNET_TIME_Relative timeout,
1753                      GST_NeighbourSendContinuation cont,
1754                      void *cont_cls)
1755 {
1756   struct NeighbourMapEntry *n;
1757   struct MessageQueue *mq;
1758
1759   /* All ove these cases should never happen; they are all API violations.
1760      But we check anyway, just to be sure. */
1761   if (NULL == (n = lookup_neighbour (target)))
1762   {
1763     GNUNET_break (0);
1764     if (NULL != cont)
1765       cont (cont_cls,
1766             GNUNET_SYSERR,
1767             msg_size,
1768             0);
1769     return;
1770   }
1771   if (GNUNET_YES != test_connected (n))
1772   {
1773     GNUNET_break (0);
1774     if (NULL != cont)
1775       cont (cont_cls,
1776             GNUNET_SYSERR,
1777             msg_size,
1778             0);
1779     return;
1780   }
1781   bytes_in_send_queue += msg_size;
1782   GNUNET_STATISTICS_set (GST_stats,
1783                          gettext_noop
1784                          ("# bytes in message queue for other peers"),
1785                          bytes_in_send_queue, GNUNET_NO);
1786   mq = GNUNET_malloc (sizeof (struct MessageQueue) + msg_size);
1787   mq->cont = cont;
1788   mq->cont_cls = cont_cls;
1789   GNUNET_memcpy (&mq[1], msg, msg_size);
1790   mq->message_buf = (const char *) &mq[1];
1791   mq->message_buf_size = msg_size;
1792   mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1793
1794   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1795               "Enqueueing %u bytes to send to peer %s\n",
1796               (unsigned int) msg_size,
1797               GNUNET_i2s (target));
1798   GNUNET_CONTAINER_DLL_insert_tail (n->messages_head,
1799                                     n->messages_tail,
1800                                     mq);
1801   if (NULL != n->task)
1802     GNUNET_SCHEDULER_cancel (n->task);
1803   n->task = GNUNET_SCHEDULER_add_now (&master_task, n);
1804 }
1805
1806
1807 /**
1808  * Continuation called from our attempt to transmitted our
1809  * #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN to the specified @a
1810  * target.  Continue processing based on the @a result.  Specifically,
1811  * if we failed to transmit, discard the address we used.
1812  *
1813  * @param cls NULL
1814  * @param target which peer received the transmission
1815  * @param result #GNUNET_OK if sending worked
1816  * @param size_payload how many bytes of payload were sent (ignored)
1817  * @param size_on_wire how much bandwidth was consumed on the wire (ignored)
1818  */
1819 static void
1820 send_session_syn_cont (void *cls,
1821                        const struct GNUNET_PeerIdentity *target,
1822                        int result,
1823                        size_t size_payload,
1824                        size_t size_on_wire)
1825 {
1826   struct NeighbourMapEntry *n;
1827
1828   (void) cls;
1829   (void) size_payload;
1830   (void) size_on_wire;
1831   n = lookup_neighbour (target);
1832   if (NULL == n)
1833   {
1834     /* SYN continuation was called after neighbor was freed,
1835      * for example due to a time out for the state or the session
1836      * used was already terminated: nothing to do here... */
1837     return;
1838   }
1839
1840   if ( (GNUNET_TRANSPORT_PS_SYN_SENT != n->state) &&
1841        (GNUNET_TRANSPORT_PS_RECONNECT_SENT != n->state) &&
1842        (GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT != n->state))
1843   {
1844     /* SYN continuation was called after neighbor changed state,
1845      * for example due to a time out for the state or the session
1846      * used was already terminated: nothing to do here... */
1847     return;
1848   }
1849   if (GNUNET_OK == result)
1850     return;
1851
1852   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1853               _("Failed to send SYN message to peer `%s'\n"),
1854               GNUNET_i2s (target));
1855   switch (n->state) {
1856   case GNUNET_TRANSPORT_PS_SYN_SENT:
1857     /* Remove address and request an additional one */
1858     unset_primary_address (n);
1859     set_state_and_timeout (n,
1860                            GNUNET_TRANSPORT_PS_INIT_ATS,
1861                            GNUNET_TIME_relative_to_absolute (FAST_RECONNECT_TIMEOUT));
1862     break;
1863   case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
1864     /* Remove address and request an additional one */
1865     unset_primary_address (n);
1866     set_state_and_timeout (n,
1867                            GNUNET_TRANSPORT_PS_RECONNECT_ATS,
1868                            GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT));
1869     break;
1870   case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
1871     /* Remove address and request and go back to primary address */
1872     GNUNET_STATISTICS_update (GST_stats,
1873                               gettext_noop ("# Failed attempts to switch addresses (failed to send SYN CONT)"),
1874                               1,
1875                               GNUNET_NO);
1876     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1877                 "Switch failed, cleaning up alternative address\n");
1878     free_address (&n->alternative_address);
1879     set_state_and_timeout (n,
1880                            GNUNET_TRANSPORT_PS_CONNECTED,
1881                            GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT));
1882     break;
1883   default:
1884     disconnect_neighbour (n);
1885     break;
1886   }
1887 }
1888
1889
1890 /**
1891  * Send a SYN message via the given address.
1892  *
1893  * @param na address to use
1894  */
1895 static void
1896 send_syn (struct NeighbourAddress *na)
1897 {
1898   struct GNUNET_TRANSPORT_PluginFunctions *papi;
1899   struct TransportSynMessage connect_msg;
1900   struct NeighbourMapEntry *n;
1901
1902   GNUNET_assert (NULL != na->session);
1903   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1904               "Sending SYN message to peer `%s' at %s\n",
1905               GNUNET_i2s (&na->address->peer),
1906               GST_plugins_a2s (na->address));
1907
1908   papi = GST_plugins_find (na->address->transport_name);
1909   GNUNET_assert (NULL != papi);
1910   GNUNET_STATISTICS_update (GST_stats,
1911                             gettext_noop
1912                             ("# SYN messages sent"),
1913                             1, GNUNET_NO);
1914   na->connect_timestamp = GNUNET_TIME_absolute_get ();
1915   connect_msg.header.size = htons (sizeof (struct TransportSynMessage));
1916   connect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN);
1917   connect_msg.reserved = htonl (0);
1918   connect_msg.timestamp = GNUNET_TIME_absolute_hton (na->connect_timestamp);
1919   if (-1 ==
1920       papi->send (papi->cls,
1921                   na->session,
1922                   (const char *) &connect_msg,
1923                   sizeof (struct TransportSynMessage),
1924                   UINT_MAX,
1925                   SETUP_CONNECTION_TIMEOUT,
1926                   &send_session_syn_cont, NULL))
1927   {
1928     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1929                 _("Failed to transmit SYN message to %s\n"),
1930                 GST_plugins_a2s (na->address));
1931     n = lookup_neighbour (&na->address->peer);
1932     if (NULL == n)
1933     {
1934       GNUNET_break (0);
1935       return;
1936     }
1937     switch (n->state) {
1938       case GNUNET_TRANSPORT_PS_SYN_SENT:
1939         /* Remove address and request and additional one */
1940         GNUNET_assert (na == &n->primary_address);
1941         unset_primary_address (n);
1942         set_state_and_timeout (n,
1943                                GNUNET_TRANSPORT_PS_INIT_ATS,
1944                                GNUNET_TIME_relative_to_absolute (FAST_RECONNECT_TIMEOUT));
1945         /* Hard failure to send the SYN message with this address:
1946            Destroy address and session */
1947         break;
1948       case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
1949         /* Remove address and request an additional one */
1950         GNUNET_assert (na == &n->primary_address);
1951         unset_primary_address (n);
1952         set_state_and_timeout (n,
1953                                GNUNET_TRANSPORT_PS_RECONNECT_ATS,
1954                                GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT));
1955         break;
1956       case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
1957         GNUNET_assert (na == &n->alternative_address);
1958         GNUNET_STATISTICS_update (GST_stats,
1959                                   gettext_noop ("# Failed attempts to switch addresses (failed to send SYN)"),
1960                                   1,
1961                                   GNUNET_NO);
1962         /* Remove address and request an additional one */
1963         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1964                     "Switch failed, cleaning up alternative address\n");
1965         free_address (&n->alternative_address);
1966         set_state_and_timeout (n,
1967                                GNUNET_TRANSPORT_PS_CONNECTED,
1968                                GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT));
1969         break;
1970       default:
1971         GNUNET_break (0);
1972         disconnect_neighbour (n);
1973         break;
1974     }
1975     return;
1976   }
1977   GST_neighbours_notify_data_sent (na->address,
1978                                    na->session,
1979                                    sizeof (struct TransportSynMessage));
1980 }
1981
1982
1983 /**
1984  * Continuation called from our attempt to transmitted our
1985  * #GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN_ACK to the specified @a
1986  * target.  Continue processing based on the @a result.  Specifically,
1987  * if we failed to transmit, discard the address we used.
1988  *
1989  * @param cls NULL
1990  * @param target which peer received the transmission
1991  * @param result #GNUNET_OK if sending worked
1992  * @param size_payload how many bytes of payload were sent (ignored)
1993  * @param size_on_wire how much bandwidth was consumed on the wire (ignored)
1994  */
1995 static void
1996 send_session_syn_ack_cont (void *cls,
1997                            const struct GNUNET_PeerIdentity *target,
1998                            int result,
1999                            size_t size_payload,
2000                            size_t size_on_wire)
2001 {
2002   struct NeighbourMapEntry *n;
2003
2004   (void) cls;
2005   (void) size_payload;
2006   (void) size_on_wire;
2007   n = lookup_neighbour (target);
2008   if (NULL == n)
2009   {
2010     /* SYN_ACK continuation was called after neighbor was freed,
2011      * for example due to a time out for the state or the session
2012      * used was already terminated: nothing to do here... */
2013     return;
2014   }
2015
2016   if (GNUNET_TRANSPORT_PS_SYN_RECV_ACK != n->state)
2017   {
2018     /* SYN_ACK continuation was called after neighbor changed state,
2019      * for example due to a time out for the state or the session
2020      * used was already terminated: nothing to do here... */
2021     return;
2022   }
2023   if (GNUNET_OK == result)
2024     return;
2025
2026   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2027             _("Failed to send SYN_ACK message to peer `%s' using address `%s'\n"),
2028             GNUNET_i2s (target),
2029             GST_plugins_a2s (n->primary_address.address));
2030
2031   /* Remove address and request and additional one */
2032   /* FIXME: what if the neighbour's primary address
2033      changed in the meantime? Might want to instead
2034      pass "something" around in closure to be sure. */
2035   unset_primary_address (n);
2036   n->ack_state = ACK_SEND_SYN_ACK;
2037   set_state_and_timeout (n,
2038                          GNUNET_TRANSPORT_PS_SYN_RECV_ATS,
2039                          GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT));
2040 }
2041
2042
2043 /**
2044  * Send a SYN_ACK message via the given address.
2045  *
2046  * @param na address and session to use
2047  * @param timestamp timestamp to use for the ACK message
2048  * @return #GNUNET_SYSERR if sending immediately failed, #GNUNET_OK otherwise
2049  */
2050 static void
2051 send_syn_ack_message (struct NeighbourAddress *na,
2052                       struct GNUNET_TIME_Absolute timestamp)
2053 {
2054   const struct GNUNET_HELLO_Address *address = na->address;
2055   struct GNUNET_ATS_Session *session = na->session;
2056   struct GNUNET_TRANSPORT_PluginFunctions *papi;
2057   struct TransportSynMessage connect_msg;
2058   struct NeighbourMapEntry *n;
2059
2060   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2061               "Sending SYN_ACK to peer `%s'\n",
2062               GNUNET_i2s (&address->peer));
2063
2064   if (NULL == (papi = GST_plugins_find (address->transport_name)))
2065   {
2066     GNUNET_break (0);
2067     return;
2068   }
2069   if (NULL == session)
2070     session = papi->get_session (papi->cls,
2071                                  address);
2072   if (NULL == session)
2073   {
2074     GNUNET_break (0);
2075     return;
2076   }
2077   GST_ats_new_session (address,
2078                        session);
2079   GNUNET_STATISTICS_update (GST_stats,
2080                             gettext_noop
2081                             ("# SYN_ACK messages sent"),
2082                             1, GNUNET_NO);
2083   connect_msg.header.size = htons (sizeof (struct TransportSynMessage));
2084   connect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN_ACK);
2085   connect_msg.reserved = htonl (0);
2086   connect_msg.timestamp = GNUNET_TIME_absolute_hton (timestamp);
2087
2088   if (GNUNET_SYSERR ==
2089       papi->send (papi->cls,
2090                   session,
2091                   (const char *) &connect_msg,
2092                   sizeof (struct TransportSynMessage),
2093                   UINT_MAX,
2094                   GNUNET_TIME_UNIT_FOREVER_REL,
2095                   &send_session_syn_ack_cont, NULL))
2096   {
2097     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2098                 _("Failed to transmit SYN_ACK message to %s\n"),
2099                 GST_plugins_a2s (address));
2100
2101     n = lookup_neighbour (&address->peer);
2102     if (NULL == n)
2103     {
2104       GNUNET_break (0);
2105       return;
2106     }
2107     /* Remove address and request and additional one */
2108     unset_primary_address (n);
2109     n->ack_state = ACK_SEND_SYN_ACK;
2110     set_state_and_timeout (n,
2111                            GNUNET_TRANSPORT_PS_SYN_RECV_ATS,
2112                            GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT));
2113     return;
2114   }
2115 }
2116
2117
2118 /**
2119  * Function called by the bandwidth tracker for a peer whenever
2120  * the tracker's state changed such that we need to recalculate
2121  * the delay for flow control.  We calculate the latest delay
2122  * and inform the plugin (if applicable).
2123  *
2124  * @param cls the `struct NeighbourMapEntry` to update calculations for
2125  */
2126 static void
2127 inbound_bw_tracker_update (void *cls)
2128 {
2129   struct NeighbourMapEntry *n = cls;
2130   struct GNUNET_TRANSPORT_PluginFunctions *papi;
2131   struct GNUNET_TIME_Relative delay;
2132   int do_forward;
2133
2134   if (NULL == n->primary_address.address)
2135     return; /* not active, ignore */
2136   papi = GST_plugins_find (n->primary_address.address->transport_name);
2137   GNUNET_assert (NULL != papi);
2138   if (NULL == papi->update_inbound_delay)
2139     return;
2140   delay = GST_neighbours_calculate_receive_delay (&n->id,
2141                                                   0,
2142                                                   &do_forward);
2143   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2144               "New inbound delay for peer `%s' is %llu ms\n",
2145               GNUNET_i2s (&n->id),
2146               (unsigned long long) delay.rel_value_us / 1000LL);
2147   if (NULL == n->primary_address.session)
2148     return;
2149   papi->update_inbound_delay (papi->cls,
2150                               &n->id,
2151                               n->primary_address.session,
2152                               delay);
2153 }
2154
2155
2156 /**
2157  * Create a fresh entry in the neighbour map for the given peer
2158  *
2159  * @param peer peer to create an entry for
2160  * @return new neighbour map entry
2161  */
2162 static struct NeighbourMapEntry *
2163 setup_neighbour (const struct GNUNET_PeerIdentity *peer)
2164 {
2165   struct NeighbourMapEntry *n;
2166
2167   if (0 ==
2168       memcmp (&GST_my_identity,
2169               peer,
2170               sizeof (struct GNUNET_PeerIdentity)))
2171   {
2172     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2173                 "Cowardly refusing to consider myself my neighbour!\n");
2174     return NULL;
2175   }
2176   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2177               "Creating new neighbour entry for `%s'\n",
2178               GNUNET_i2s (peer));
2179   n = GNUNET_new (struct NeighbourMapEntry);
2180   n->id = *peer;
2181   n->ack_state = ACK_UNDEFINED;
2182   n->last_util_transmission = GNUNET_TIME_absolute_get();
2183   n->neighbour_receive_quota = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
2184   GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
2185                                  &inbound_bw_tracker_update,
2186                                  n,
2187                                  GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
2188                                  MAX_BANDWIDTH_CARRY_S);
2189   n->task = GNUNET_SCHEDULER_add_now (&master_task, n);
2190   set_state_and_timeout (n,
2191                          GNUNET_TRANSPORT_PS_NOT_CONNECTED,
2192                          GNUNET_TIME_UNIT_FOREVER_ABS);
2193   GNUNET_assert (GNUNET_OK ==
2194                  GNUNET_CONTAINER_multipeermap_put (neighbours,
2195                                                     &n->id,
2196                                                     n,
2197                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2198   n->suggest_handle = GNUNET_ATS_connectivity_suggest (GST_ats_connect,
2199                                                        peer,
2200                                                        0);
2201
2202   return n;
2203 }
2204
2205
2206 /**
2207  * Entry in a DLL we use to keep track of pending blacklist checks.
2208  */
2209 struct BlacklistCheckSwitchContext
2210 {
2211   /**
2212    * DLL prev pointer.
2213    */
2214   struct BlacklistCheckSwitchContext *prev;
2215
2216   /**
2217    * DLL next pointer.
2218    */
2219   struct BlacklistCheckSwitchContext *next;
2220
2221   /**
2222    * Handle to the blacklist check we are performing.
2223    */
2224   struct GST_BlacklistCheck *blc;
2225
2226   /**
2227    * Inbound bandwidth that was assigned to @e address.
2228    */
2229   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
2230
2231   /**
2232    * Outbound bandwidth that was assigned to @e address.
2233    */
2234   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
2235 };
2236
2237
2238 /**
2239  * We received a 'SYN' message from the other peer.
2240  * Consider switching to it.
2241  *
2242  * @param message possibly a `struct TransportSynMessage` (check format)
2243  * @param peer identity of the peer to switch the address for
2244  * @return #GNUNET_OK if the message was fine, #GNUNET_SYSERR on serious error
2245  */
2246 int
2247 GST_neighbours_handle_session_syn (const struct GNUNET_MessageHeader *message,
2248                                    const struct GNUNET_PeerIdentity *peer)
2249 {
2250   const struct TransportSynMessage *scm;
2251   struct NeighbourMapEntry *n;
2252   struct GNUNET_TIME_Absolute ts;
2253
2254   if (ntohs (message->size) != sizeof (struct TransportSynMessage))
2255   {
2256     GNUNET_break_op (0);
2257     return GNUNET_SYSERR;
2258   }
2259   GNUNET_STATISTICS_update (GST_stats,
2260                             gettext_noop
2261                             ("# SYN messages received"),
2262                             1, GNUNET_NO);
2263   if (NULL == neighbours)
2264   {
2265     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2266                 _("SYN request from peer `%s' ignored due impending shutdown\n"),
2267                 GNUNET_i2s (peer));
2268     return GNUNET_OK; /* we're shutting down */
2269   }
2270   scm = (const struct TransportSynMessage *) message;
2271   GNUNET_break_op (0 == ntohl (scm->reserved));
2272   ts = GNUNET_TIME_absolute_ntoh (scm->timestamp);
2273   if (0 ==
2274       memcmp (&GST_my_identity,
2275               peer,
2276               sizeof (struct GNUNET_PeerIdentity)))
2277   {
2278     /* loopback connection-to-self, ignore */
2279     return GNUNET_SYSERR;
2280   }
2281   n = lookup_neighbour (peer);
2282   if (NULL == n)
2283   {
2284     /* This is a new neighbour and set to not connected */
2285     n = setup_neighbour (peer);
2286     GNUNET_assert (NULL != n);
2287   }
2288
2289   /* Remember this SYN message in neighbour */
2290   n->ack_state = ACK_SEND_SYN_ACK;
2291   n->connect_ack_timestamp = ts;
2292
2293   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2294               "Received SYN for peer `%s' in state %s/%s\n",
2295               GNUNET_i2s (peer),
2296               GNUNET_TRANSPORT_ps2s (n->state),
2297               print_ack_state (n->ack_state));
2298
2299   switch (n->state)
2300   {
2301   case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
2302     /* Request an address from ATS to send SYN_ACK to this peer */
2303     set_state_and_timeout (n,
2304                            GNUNET_TRANSPORT_PS_SYN_RECV_ATS,
2305                            GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT));
2306     break;
2307   case GNUNET_TRANSPORT_PS_INIT_ATS:
2308     /* SYN message takes priority over us asking ATS for address:
2309      * Wait for ATS to suggest an address and send SYN_ACK */
2310     set_state_and_timeout (n,
2311                            GNUNET_TRANSPORT_PS_SYN_RECV_ATS,
2312                            GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT));
2313     break;
2314   case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
2315     /* We already wait for an address to send an SYN_ACK */
2316     break;
2317   case GNUNET_TRANSPORT_PS_SYN_SENT:
2318   case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
2319     /* Send ACK immediately */
2320     n->ack_state = ACK_SEND_ACK;
2321     send_syn_ack_message (&n->primary_address,
2322                           ts);
2323     break;
2324   case GNUNET_TRANSPORT_PS_CONNECTED:
2325     /* we are already connected and can thus send the ACK immediately */
2326     GNUNET_assert (NULL != n->primary_address.address);
2327     GNUNET_assert (NULL != n->primary_address.session);
2328     n->ack_state = ACK_SEND_ACK;
2329     send_syn_ack_message (&n->primary_address,
2330                           ts);
2331     break;
2332   case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
2333     /* We wait for ATS address suggestion */
2334     break;
2335   case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
2336     /* We received a SYN message while waiting for a SYN_ACK in fast
2337      * reconnect. Send SYN_ACK immediately */
2338     n->ack_state = ACK_SEND_ACK;
2339     send_syn_ack_message (&n->primary_address,
2340                           n->connect_ack_timestamp);
2341     break;
2342   case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
2343     /* We are already connected and can thus send the ACK immediately;
2344        still, it can never hurt to have an alternative address, so also
2345        tell ATS  about it */
2346     GNUNET_assert (NULL != n->primary_address.address);
2347     GNUNET_assert (NULL != n->primary_address.session);
2348     n->ack_state = ACK_SEND_ACK;
2349     send_syn_ack_message (&n->primary_address,
2350                           ts);
2351     break;
2352   case GNUNET_TRANSPORT_PS_DISCONNECT:
2353     /* Get rid of remains and re-try */
2354     free_neighbour (n);
2355     n = setup_neighbour (peer);
2356     GNUNET_assert (NULL != n);
2357     /* Remember the SYN time stamp for ACK message */
2358     n->ack_state = ACK_SEND_SYN_ACK;
2359     n->connect_ack_timestamp = ts;
2360     /* Request an address for the peer */
2361     set_state_and_timeout (n,
2362                            GNUNET_TRANSPORT_PS_SYN_RECV_ATS,
2363                            GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT));
2364     break;
2365   case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
2366     /* should not be possible */
2367     GNUNET_assert (0);
2368     break;
2369   default:
2370     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2371                 "Unhandled state `%s'\n",
2372                 GNUNET_TRANSPORT_ps2s (n->state));
2373     GNUNET_break (0);
2374     return GNUNET_SYSERR;
2375   }
2376   return GNUNET_OK;
2377 }
2378
2379
2380 /**
2381  * Check if the given @a address is the same that we are already
2382  * using for the respective neighbour. If so, update the bandwidth
2383  * assignment and possibly the session and return #GNUNET_OK.
2384  * If the new address is different from what the neighbour is
2385  * using right now, return #GNUNET_NO.
2386  *
2387  * @param address address of the other peer,
2388  * @param session session to use or NULL if transport should initiate a session
2389  * @param bandwidth_in inbound quota to be used when connection is up,
2390  *      0 to disconnect from peer
2391  * @param bandwidth_out outbound quota to be used when connection is up,
2392  *      0 to disconnect from peer
2393  * @return #GNUNET_OK if we were able to just update the bandwidth and session,
2394  *         #GNUNET_NO if more extensive changes are required (address changed)
2395  */
2396 static int
2397 try_run_fast_ats_update (const struct GNUNET_HELLO_Address *address,
2398                          struct GNUNET_ATS_Session *session,
2399                          struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
2400                          struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
2401 {
2402   struct NeighbourMapEntry *n;
2403
2404   n = lookup_neighbour (&address->peer);
2405   if ( (NULL == n) ||
2406        (NULL == n->primary_address.address) ||
2407        (0 != GNUNET_HELLO_address_cmp (address,
2408                                        n->primary_address.address)) )
2409     return GNUNET_NO;
2410   /* We are not really switching addresses, but merely adjusting
2411      session and/or bandwidth, can do fast ATS update! */
2412   if (session != n->primary_address.session)
2413   {
2414     /* switch to a different session, but keeping same address; could
2415        happen if there is a 2nd inbound connection */
2416     n->primary_address.session = session;
2417     GNUNET_assert (GNUNET_YES ==
2418                    GST_ats_is_known (n->primary_address.address,
2419                                      n->primary_address.session));
2420   }
2421   if (n->primary_address.bandwidth_in.value__ != bandwidth_in.value__)
2422   {
2423     n->primary_address.bandwidth_in = bandwidth_in;
2424     if (GNUNET_YES !=
2425         set_incoming_quota (n,
2426                             bandwidth_in))
2427       return GNUNET_NO;
2428   }
2429   if (n->primary_address.bandwidth_out.value__ != bandwidth_out.value__)
2430   {
2431     n->primary_address.bandwidth_out = bandwidth_out;
2432     send_outbound_quota_to_clients (n);
2433   }
2434   return GNUNET_OK;
2435 }
2436
2437
2438 /**
2439  * We've been asked to switch addresses, and just now got the result
2440  * from the blacklist check to see if this is allowed.
2441  *
2442  * @param cls the `struct BlacklistCheckSwitchContext` with
2443  *        the information about the future address
2444  * @param peer the peer we may switch addresses on
2445  * @param address address associated with the request
2446  * @param session session associated with the request
2447  * @param result #GNUNET_OK if the connection is allowed,
2448  *               #GNUNET_NO if not,
2449  *               #GNUNET_SYSERR if operation was aborted
2450  */
2451 static void
2452 switch_address_bl_check_cont (void *cls,
2453                               const struct GNUNET_PeerIdentity *peer,
2454                               const struct GNUNET_HELLO_Address *address,
2455                               struct GNUNET_ATS_Session *session,
2456                               int result)
2457 {
2458   struct BlacklistCheckSwitchContext *blc_ctx = cls;
2459   struct GNUNET_TRANSPORT_PluginFunctions *papi;
2460   struct NeighbourMapEntry *n;
2461
2462   if (GNUNET_SYSERR == result)
2463     goto cleanup;
2464
2465   papi = GST_plugins_find (address->transport_name);
2466   if (NULL == papi) {
2467     /* This can happen during shutdown. */
2468     goto cleanup;
2469   }
2470
2471   if (GNUNET_NO == result)
2472   {
2473     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2474                 "Blacklist denied to switch to suggested address `%s' session %p for peer `%s'\n",
2475                 GST_plugins_a2s (address),
2476                 session,
2477                 GNUNET_i2s (peer));
2478     GNUNET_STATISTICS_update (GST_stats,
2479                               "# ATS suggestions ignored (blacklist denied)",
2480                               1,
2481                               GNUNET_NO);
2482     if (NULL != session)
2483       papi->disconnect_session (papi->cls,
2484                                 session);
2485     if (GNUNET_YES !=
2486         GNUNET_HELLO_address_check_option (address,
2487                                            GNUNET_HELLO_ADDRESS_INFO_INBOUND))
2488       GST_ats_block_address (address,
2489                              NULL);
2490     goto cleanup;
2491   }
2492
2493
2494   if (NULL == session)
2495   {
2496     /* need to create a session, ATS only gave us an address */
2497     session = papi->get_session (papi->cls,
2498                                  address);
2499     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2500                 "Obtained new session for peer `%s' and  address '%s': %p\n",
2501                 GNUNET_i2s (&address->peer),
2502                 GST_plugins_a2s (address),
2503                 session);
2504     if (NULL != session)
2505       GST_ats_new_session (address,
2506                            session);
2507   }
2508   if (NULL == session)
2509   {
2510     /* session creation failed, bad!, fail! */
2511     GNUNET_STATISTICS_update (GST_stats,
2512                               "# ATS suggestions ignored (failed to create session)",
2513                               1,
2514                               GNUNET_NO);
2515     /* No session could be obtained, remove blacklist check and clean up */
2516     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2517                 "Failed to obtain new session for peer `%s' and address '%s'\n",
2518                 GNUNET_i2s (&address->peer),
2519                 GST_plugins_a2s (address));
2520     GST_ats_block_address (address,
2521                            session);
2522     goto cleanup;
2523   }
2524
2525   /* We did this check already before going into blacklist, but
2526      it is theoretically possible that the situation changed in
2527      the meantime, hence we check again here */
2528   if (GNUNET_OK ==
2529       try_run_fast_ats_update (address,
2530                                session,
2531                                blc_ctx->bandwidth_in,
2532                                blc_ctx->bandwidth_out))
2533     goto cleanup; /* was just a minor update, we're done */
2534
2535   /* check if we also need to setup the neighbour entry */
2536   if (NULL == (n = lookup_neighbour (peer)))
2537   {
2538     n = setup_neighbour (peer);
2539     if (NULL == n)
2540     {
2541       /* not sure how this can happen... */
2542       GNUNET_break (0);
2543       goto cleanup;
2544     }
2545     n->state = GNUNET_TRANSPORT_PS_INIT_ATS;
2546   }
2547
2548   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2549               "Peer `%s' switches to address `%s'\n",
2550               GNUNET_i2s (&address->peer),
2551               GST_plugins_a2s (address));
2552
2553   switch (n->state)
2554   {
2555   case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
2556     GNUNET_break (0);
2557     GST_ats_block_address (address,
2558                            session);
2559     free_neighbour (n);
2560     return;
2561   case GNUNET_TRANSPORT_PS_INIT_ATS:
2562     /* We requested an address and ATS suggests one:
2563      * set primary address and send SYN message*/
2564     set_primary_address (n,
2565                          address,
2566                          session,
2567                          blc_ctx->bandwidth_in,
2568                          blc_ctx->bandwidth_out);
2569     if (ACK_SEND_SYN_ACK == n->ack_state)
2570     {
2571       /* Send pending SYN_ACK message */
2572       n->ack_state = ACK_SEND_ACK;
2573       send_syn_ack_message (&n->primary_address,
2574                             n->connect_ack_timestamp);
2575     }
2576     set_state_and_timeout (n,
2577                            GNUNET_TRANSPORT_PS_SYN_SENT,
2578                            GNUNET_TIME_relative_to_absolute (SETUP_CONNECTION_TIMEOUT));
2579     send_syn (&n->primary_address);
2580     break;
2581   case GNUNET_TRANSPORT_PS_SYN_SENT:
2582     /* ATS suggested a new address while waiting for an SYN_ACK:
2583      * Switch and send new SYN */
2584     /* ATS suggests a different address, switch again */
2585     set_primary_address (n,
2586                          address,
2587                          session,
2588                          blc_ctx->bandwidth_in,
2589                          blc_ctx->bandwidth_out);
2590     if (ACK_SEND_SYN_ACK == n->ack_state)
2591     {
2592       /* Send pending SYN_ACK message */
2593       n->ack_state = ACK_SEND_ACK;
2594       send_syn_ack_message (&n->primary_address,
2595                             n->connect_ack_timestamp);
2596     }
2597     set_state_and_timeout (n,
2598                            GNUNET_TRANSPORT_PS_SYN_SENT,
2599                            GNUNET_TIME_relative_to_absolute (SETUP_CONNECTION_TIMEOUT));
2600     send_syn (&n->primary_address);
2601     break;
2602   case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
2603     /* We requested an address and ATS suggests one:
2604      * set primary address and send SYN_ACK message*/
2605     set_primary_address (n,
2606                          address,
2607                          session,
2608                          blc_ctx->bandwidth_in,
2609                          blc_ctx->bandwidth_out);
2610     /* Send an ACK message as a response to the SYN msg */
2611     set_state_and_timeout (n,
2612                            GNUNET_TRANSPORT_PS_SYN_RECV_ACK,
2613                            GNUNET_TIME_relative_to_absolute (SETUP_CONNECTION_TIMEOUT));
2614     send_syn_ack_message (&n->primary_address,
2615                           n->connect_ack_timestamp);
2616     if ( (ACK_SEND_SYN_ACK == n->ack_state) ||
2617          (ACK_UNDEFINED == n->ack_state) )
2618       n->ack_state = ACK_SEND_ACK;
2619     break;
2620   case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
2621     /* ATS asks us to switch while we were trying to connect; switch to new
2622        address and check blacklist again */
2623     if ( (ACK_SEND_SYN_ACK == n->ack_state) )
2624     {
2625       n->ack_state = ACK_SEND_ACK;
2626       send_syn_ack_message (&n->primary_address,
2627                             n->connect_ack_timestamp);
2628     }
2629     set_primary_address (n,
2630                          address,
2631                          session,
2632                          blc_ctx->bandwidth_in,
2633                          blc_ctx->bandwidth_out);
2634     set_state_and_timeout (n,
2635                            GNUNET_TRANSPORT_PS_SYN_RECV_ACK,
2636                            GNUNET_TIME_relative_to_absolute (SETUP_CONNECTION_TIMEOUT));
2637     break;
2638   case GNUNET_TRANSPORT_PS_CONNECTED:
2639     GNUNET_assert (NULL != n->primary_address.address);
2640     GNUNET_assert (NULL != n->primary_address.session);
2641     GNUNET_break (n->primary_address.session != session);
2642     /* ATS asks us to switch a life connection; see if we can get
2643        a SYN_ACK on it before we actually do this! */
2644     set_alternative_address (n,
2645                              address,
2646                              session,
2647                              blc_ctx->bandwidth_in,
2648                              blc_ctx->bandwidth_out);
2649     set_state_and_timeout (n,
2650                            GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT,
2651                            GNUNET_TIME_relative_to_absolute (SETUP_CONNECTION_TIMEOUT));
2652     GNUNET_STATISTICS_update (GST_stats,
2653                               gettext_noop ("# Attempts to switch addresses"),
2654                               1,
2655                               GNUNET_NO);
2656     send_syn (&n->alternative_address);
2657     break;
2658   case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
2659     set_primary_address (n,
2660                          address,
2661                          session,
2662                          blc_ctx->bandwidth_in,
2663                          blc_ctx->bandwidth_out);
2664     if (ACK_SEND_SYN_ACK == n->ack_state)
2665     {
2666       /* Send pending SYN_ACK message */
2667       n->ack_state = ACK_SEND_ACK;
2668       send_syn_ack_message (&n->primary_address,
2669                             n->connect_ack_timestamp);
2670     }
2671     set_state_and_timeout (n,
2672                            GNUNET_TRANSPORT_PS_RECONNECT_SENT,
2673                            GNUNET_TIME_relative_to_absolute (FAST_RECONNECT_TIMEOUT));
2674     send_syn (&n->primary_address);
2675     break;
2676   case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
2677     /* ATS asks us to switch while we were trying to reconnect; switch to new
2678        address and send SYN again */
2679     set_primary_address (n,
2680                          address,
2681                          session,
2682                          blc_ctx->bandwidth_in,
2683                          blc_ctx->bandwidth_out);
2684     set_state_and_timeout (n,
2685                            GNUNET_TRANSPORT_PS_RECONNECT_SENT,
2686                            GNUNET_TIME_relative_to_absolute (FAST_RECONNECT_TIMEOUT));
2687     send_syn (&n->primary_address);
2688     break;
2689   case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
2690     if ( (0 == GNUNET_HELLO_address_cmp (n->primary_address.address,
2691                                          address)) &&
2692          (n->primary_address.session == session) )
2693     {
2694       /* ATS switches back to still-active session */
2695       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2696                   "ATS double-switched, cleaning up alternative address\n");
2697       free_address (&n->alternative_address);
2698       set_state_and_timeout (n,
2699                              GNUNET_TRANSPORT_PS_CONNECTED,
2700                              n->timeout);
2701       break;
2702     }
2703     /* ATS asks us to switch a life connection, send */
2704     set_alternative_address (n,
2705                              address,
2706                              session,
2707                              blc_ctx->bandwidth_in,
2708                              blc_ctx->bandwidth_out);
2709     set_state_and_timeout (n,
2710                            GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT,
2711                            GNUNET_TIME_relative_to_absolute (SETUP_CONNECTION_TIMEOUT));
2712     send_syn (&n->alternative_address);
2713     break;
2714   case GNUNET_TRANSPORT_PS_DISCONNECT:
2715     /* not going to switch addresses while disconnecting */
2716     GNUNET_STATISTICS_update (GST_stats,
2717                               "# ATS suggestion ignored (disconnecting)",
2718                               1,
2719                               GNUNET_NO);
2720     return;
2721   case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
2722     GNUNET_assert (0);
2723     break;
2724   default:
2725     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2726                 "Unhandled state `%s'\n",
2727                 GNUNET_TRANSPORT_ps2s (n->state));
2728     GNUNET_break (0);
2729     break;
2730   }
2731  cleanup:
2732   GNUNET_CONTAINER_DLL_remove (pending_bc_head,
2733                                pending_bc_tail,
2734                                blc_ctx);
2735   GNUNET_free (blc_ctx);
2736 }
2737
2738
2739 /**
2740  * For the given peer, switch to this address.
2741  *
2742  * Before accepting this addresses and actively using it, a blacklist check
2743  * is performed.
2744  *
2745  * If any check fails or the suggestion can somehow not be followed, we
2746  * MUST call #GST_ats_block_address() to tell ATS that the suggestion
2747  * could not be satisfied and force ATS to do something else.
2748  *
2749  * @param address address of the other peer,
2750  * @param session session to use or NULL if transport should initiate a session
2751  * @param bandwidth_in inbound quota to be used when connection is up,
2752  *      0 to disconnect from peer
2753  * @param bandwidth_out outbound quota to be used when connection is up,
2754  *      0 to disconnect from peer
2755  */
2756 void
2757 GST_neighbours_switch_to_address (const struct GNUNET_HELLO_Address *address,
2758                                   struct GNUNET_ATS_Session *session,
2759                                   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
2760                                   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
2761 {
2762   struct GST_BlacklistCheck *blc;
2763   struct BlacklistCheckSwitchContext *blc_ctx;
2764
2765   GNUNET_assert (NULL != address->transport_name);
2766   if (GNUNET_OK ==
2767       try_run_fast_ats_update (address,
2768                                session,
2769                                bandwidth_in,
2770                                bandwidth_out))
2771     return;
2772
2773   /* Check if plugin is available */
2774   if (NULL == (GST_plugins_find (address->transport_name)))
2775   {
2776     /* we don't have the plugin for this address */
2777     GNUNET_break (0);
2778     GST_ats_block_address (address,
2779                            session);
2780     return;
2781   }
2782   if ((NULL == session) &&
2783       (GNUNET_HELLO_address_check_option (address,
2784                                           GNUNET_HELLO_ADDRESS_INFO_INBOUND)))
2785   {
2786     /* This is a inbound address and we do not have a session to use! */
2787     GNUNET_break (0);
2788     GST_ats_block_address (address,
2789                            session);
2790     return;
2791   }
2792
2793   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2794               "ATS suggests address '%s' for peer `%s' at %u/%u speed\n",
2795               GST_plugins_a2s (address),
2796               GNUNET_i2s (&address->peer),
2797               (unsigned int) ntohl (bandwidth_in.value__),
2798               (unsigned int) ntohl (bandwidth_out.value__));
2799
2800   /* Perform blacklist check */
2801   blc_ctx = GNUNET_new (struct BlacklistCheckSwitchContext);
2802   blc_ctx->bandwidth_in = bandwidth_in;
2803   blc_ctx->bandwidth_out = bandwidth_out;
2804   GNUNET_CONTAINER_DLL_insert (pending_bc_head,
2805                                pending_bc_tail,
2806                                blc_ctx);
2807   if (NULL != (blc = GST_blacklist_test_allowed (&address->peer,
2808                                                  address->transport_name,
2809                                                  &switch_address_bl_check_cont,
2810                                                  blc_ctx,
2811                                                  address,
2812                                                  session)))
2813   {
2814     blc_ctx->blc = blc;
2815   }
2816 }
2817
2818
2819 /**
2820  * Function called to send network utilization data to ATS for
2821  * each active connection.
2822  *
2823  * @param cls NULL
2824  * @param key peer we send utilization data for
2825  * @param value the `struct NeighbourMapEntry *` with data to send
2826  * @return #GNUNET_OK (continue to iterate)
2827  */
2828 static int
2829 send_utilization_data (void *cls,
2830                        const struct GNUNET_PeerIdentity *key,
2831                        void *value)
2832 {
2833   struct NeighbourMapEntry *n = value;
2834   uint32_t bps_in;
2835   uint32_t bps_out;
2836   struct GNUNET_TIME_Relative delta;
2837
2838   (void) cls;
2839   if ( (GNUNET_YES != test_connected (n)) ||
2840        (NULL == n->primary_address.address) )
2841     return GNUNET_OK;
2842   delta = GNUNET_TIME_absolute_get_difference (n->last_util_transmission,
2843                                                GNUNET_TIME_absolute_get ());
2844   bps_in = 0;
2845   if ((0 != n->util_total_bytes_recv) && (0 != delta.rel_value_us))
2846     bps_in =  (1000LL * 1000LL *  n->util_total_bytes_recv) / (delta.rel_value_us);
2847   bps_out = 0;
2848   if ((0 != n->util_total_bytes_sent) && (0 != delta.rel_value_us))
2849     bps_out = (1000LL * 1000LL * n->util_total_bytes_sent) / delta.rel_value_us;
2850
2851   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2852               "`%s' total: received %u Bytes/s, sent %u Bytes/s\n",
2853               GNUNET_i2s (key),
2854               bps_in,
2855               bps_out);
2856   GST_ats_update_utilization (n->primary_address.address,
2857                               bps_in,
2858                               bps_out);
2859   n->util_total_bytes_recv = 0;
2860   n->util_total_bytes_sent = 0;
2861   n->last_util_transmission = GNUNET_TIME_absolute_get ();
2862   return GNUNET_OK;
2863 }
2864
2865
2866 /**
2867  * Task transmitting utilization in a regular interval
2868  *
2869  * @param cls the `struct NeighbourMapEntry` for which we are running
2870  */
2871 static void
2872 utilization_transmission (void *cls)
2873 {
2874   (void) cls;
2875   util_transmission_tk = NULL;
2876   GNUNET_CONTAINER_multipeermap_iterate (neighbours,
2877                                          &send_utilization_data,
2878                                          NULL);
2879   util_transmission_tk
2880     = GNUNET_SCHEDULER_add_delayed (UTIL_TRANSMISSION_INTERVAL,
2881                                     &utilization_transmission,
2882                                     NULL);
2883 }
2884
2885
2886 /**
2887  * Track information about data we received from the
2888  * given address (used to notify ATS about our utilization
2889  * of allocated resources).
2890  *
2891  * @param address the address we got data from
2892  * @param message the message we received (really only the size is used)
2893  */
2894 void
2895 GST_neighbours_notify_data_recv (const struct GNUNET_HELLO_Address *address,
2896                                  const struct GNUNET_MessageHeader *message)
2897 {
2898   struct NeighbourMapEntry *n;
2899
2900   n = lookup_neighbour (&address->peer);
2901   if (NULL == n)
2902     return;
2903   n->util_total_bytes_recv += ntohs (message->size);
2904 }
2905
2906
2907 /**
2908  * Track information about data we transmitted using the given @a
2909  * address and @a session (used to notify ATS about our utilization of
2910  * allocated resources).
2911  *
2912  * @param address the address we transmitted data to
2913  * @param session session we used to transmit data
2914  * @param message the message we sent (really only the size is used)
2915  */
2916 void
2917 GST_neighbours_notify_data_sent (const struct GNUNET_HELLO_Address *address,
2918                                  struct GNUNET_ATS_Session *session,
2919                                  size_t size)
2920 {
2921   struct NeighbourMapEntry *n;
2922
2923   n = lookup_neighbour (&address->peer);
2924   if (NULL == n)
2925       return;
2926   if (n->primary_address.session != session)
2927     return;
2928   n->util_total_bytes_sent += size;
2929 }
2930
2931
2932 /**
2933  * Master task run for every neighbour.  Performs all of the time-related
2934  * activities (keep alive, send next message, disconnect if idle, finish
2935  * clean up after disconnect).
2936  *
2937  * @param cls the 'struct NeighbourMapEntry' for which we are running
2938  */
2939 static void
2940 master_task (void *cls)
2941 {
2942   struct NeighbourMapEntry *n = cls;
2943   struct GNUNET_TIME_Relative delay;
2944
2945   n->task = NULL;
2946   delay = GNUNET_TIME_absolute_get_remaining (n->timeout);
2947   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2948               "Master task runs for neighbour `%s' in state %s with timeout in %s\n",
2949               GNUNET_i2s (&n->id),
2950               GNUNET_TRANSPORT_ps2s(n->state),
2951               GNUNET_STRINGS_relative_time_to_string (delay,
2952                                                       GNUNET_YES));
2953   switch (n->state)
2954   {
2955   case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
2956     /* invalid state for master task, clean up */
2957     GNUNET_break (0);
2958     free_neighbour (n);
2959     return;
2960   case GNUNET_TRANSPORT_PS_INIT_ATS:
2961     if (0 == delay.rel_value_us)
2962     {
2963       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2964                   "Connection to `%s' timed out waiting for ATS to provide address\n",
2965                   GNUNET_i2s (&n->id));
2966       free_neighbour (n);
2967       return;
2968     }
2969     break;
2970   case GNUNET_TRANSPORT_PS_SYN_SENT:
2971     if (0 == delay.rel_value_us)
2972     {
2973       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2974                   "Connection to `%s' timed out waiting for other peer to send SYN_ACK\n",
2975                   GNUNET_i2s (&n->id));
2976       /* Remove address and request and additional one */
2977       unset_primary_address (n);
2978       set_state_and_timeout (n,
2979                              GNUNET_TRANSPORT_PS_INIT_ATS,
2980                              GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT));
2981       return;
2982     }
2983     break;
2984   case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
2985     if (0 == delay.rel_value_us)
2986     {
2987       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2988                   "Connection to `%s' timed out waiting ATS to provide address to use for SYN_ACK\n",
2989                   GNUNET_i2s (&n->id));
2990       free_neighbour (n);
2991       return;
2992     }
2993     break;
2994   case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
2995     if (0 == delay.rel_value_us)
2996     {
2997       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2998                   "Connection to `%s' timed out waiting for other peer to send ACK\n",
2999                   GNUNET_i2s (&n->id));
3000       disconnect_neighbour (n);
3001       return;
3002     }
3003     break;
3004   case GNUNET_TRANSPORT_PS_CONNECTED:
3005     if (0 == delay.rel_value_us)
3006     {
3007       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3008                   "Connection to `%s' timed out, missing KEEPALIVE_RESPONSEs\n",
3009                   GNUNET_i2s (&n->id));
3010       disconnect_neighbour (n);
3011       return;
3012     }
3013     try_transmission_to_peer (n);
3014     send_keepalive (n);
3015     break;
3016   case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
3017     if (0 == delay.rel_value_us)
3018     {
3019       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3020                   "Connection to `%s' timed out, waiting for ATS replacement address\n",
3021                   GNUNET_i2s (&n->id));
3022       disconnect_neighbour (n);
3023       return;
3024     }
3025     break;
3026   case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
3027     if (0 == delay.rel_value_us)
3028     {
3029       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3030                   "Connection to `%s' timed out, waiting for other peer to SYN_ACK replacement address\n",
3031                   GNUNET_i2s (&n->id));
3032       disconnect_neighbour (n);
3033       return;
3034     }
3035     break;
3036   case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
3037     if (0 == delay.rel_value_us)
3038     {
3039       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3040                   "Switch failed, cleaning up alternative address\n");
3041       free_address (&n->alternative_address);
3042       set_state_and_timeout (n,
3043                              GNUNET_TRANSPORT_PS_CONNECTED,
3044                              GNUNET_TIME_relative_to_absolute (SETUP_CONNECTION_TIMEOUT));
3045     }
3046     try_transmission_to_peer (n);
3047     send_keepalive (n);
3048     break;
3049   case GNUNET_TRANSPORT_PS_DISCONNECT:
3050     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3051                 "Cleaning up connection to `%s' after sending DISCONNECT\n",
3052                 GNUNET_i2s (&n->id));
3053     free_neighbour (n);
3054     return;
3055   case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
3056     /* how did we get here!? */
3057     GNUNET_assert (0);
3058     break;
3059   default:
3060     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3061                 "Unhandled state `%s'\n",
3062                 GNUNET_TRANSPORT_ps2s (n->state));
3063     GNUNET_break (0);
3064     break;
3065   }
3066   delay = GNUNET_TIME_absolute_get_remaining (n->timeout);
3067   if ( (GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT == n->state) ||
3068        (GNUNET_TRANSPORT_PS_CONNECTED == n->state) )
3069   {
3070     /* if we are *now* in one of the two states, we're sending
3071        keep alive messages, so we need to consider the keepalive
3072        delay, not just the connection timeout */
3073     delay = GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining (n->keep_alive_time),
3074                                       delay);
3075   }
3076   if (NULL == n->task)
3077     n->task = GNUNET_SCHEDULER_add_delayed (delay,
3078                                             &master_task,
3079                                             n);
3080 }
3081
3082
3083 /**
3084  * Send a ACK message to the neighbour to confirm that we
3085  * got its SYN_ACK.
3086  *
3087  * @param n neighbour to send the ACK to
3088  */
3089 static void
3090 send_session_ack_message (struct NeighbourMapEntry *n)
3091 {
3092   struct GNUNET_MessageHeader msg;
3093
3094   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3095               "Sending ACK message to peer `%s'\n",
3096               GNUNET_i2s (&n->id));
3097
3098   msg.size = htons (sizeof (struct GNUNET_MessageHeader));
3099   msg.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK);
3100   (void) send_with_session (n,
3101                             &msg,
3102                             sizeof (struct GNUNET_MessageHeader),
3103                             UINT32_MAX,
3104                             GNUNET_TIME_UNIT_FOREVER_REL,
3105                             GNUNET_NO,
3106                             NULL, NULL);
3107 }
3108
3109
3110 /**
3111  * We received a 'SESSION_SYN_ACK' message from the other peer.
3112  * Consider switching to it.
3113  *
3114  * @param message possibly a `struct GNUNET_ATS_SessionConnectMessage` (check format)
3115  * @param peer identity of the peer to switch the address for
3116  * @param address address of the other peer, NULL if other peer
3117  *                       connected to us
3118  * @param session session to use (or NULL)
3119  * @return #GNUNET_OK if the message was fine, #GNUNET_SYSERR on serious error
3120  */
3121 int
3122 GST_neighbours_handle_session_syn_ack (const struct GNUNET_MessageHeader *message,
3123                                        const struct GNUNET_HELLO_Address *address,
3124                                        struct GNUNET_ATS_Session *session)
3125 {
3126   const struct TransportSynMessage *scm;
3127   struct GNUNET_TIME_Absolute ts;
3128   struct NeighbourMapEntry *n;
3129
3130   (void) session;
3131   if (ntohs (message->size) != sizeof (struct TransportSynMessage))
3132   {
3133     GNUNET_break_op (0);
3134     return GNUNET_SYSERR;
3135   }
3136   GNUNET_STATISTICS_update (GST_stats,
3137                             gettext_noop
3138                             ("# SYN_ACK messages received"),
3139                             1, GNUNET_NO);
3140   scm = (const struct TransportSynMessage *) message;
3141   GNUNET_break_op (ntohl (scm->reserved) == 0);
3142   if (NULL == (n = lookup_neighbour (&address->peer)))
3143   {
3144     GNUNET_STATISTICS_update (GST_stats,
3145                               gettext_noop
3146                               ("# unexpected SYN_ACK messages (no peer)"),
3147                               1, GNUNET_NO);
3148     return GNUNET_SYSERR;
3149   }
3150   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3151               "Received SYN_ACK message from peer `%s' in state %s/%s\n",
3152               GNUNET_i2s (&address->peer),
3153               GNUNET_TRANSPORT_ps2s (n->state),
3154               print_ack_state (n->ack_state));
3155   ts = GNUNET_TIME_absolute_ntoh (scm->timestamp);
3156   switch (n->state)
3157   {
3158   case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
3159     GNUNET_break (0);
3160     free_neighbour (n);
3161     return GNUNET_SYSERR;
3162   case GNUNET_TRANSPORT_PS_INIT_ATS:
3163     GNUNET_STATISTICS_update (GST_stats,
3164                               gettext_noop ("# unexpected SYN_ACK messages (not ready)"),
3165                               1,
3166                               GNUNET_NO);
3167     break;
3168   case GNUNET_TRANSPORT_PS_SYN_SENT:
3169     if (ts.abs_value_us != n->primary_address.connect_timestamp.abs_value_us)
3170     {
3171       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3172                   "SYN_ACK ignored as the timestamp does not match our SYN request\n");
3173       return GNUNET_OK;
3174     }
3175     set_state_and_timeout (n,
3176                            GNUNET_TRANSPORT_PS_CONNECTED,
3177                            GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT));
3178     set_primary_address (n,
3179                          n->primary_address.address,
3180                          n->primary_address.session,
3181                          n->primary_address.bandwidth_in,
3182                          n->primary_address.bandwidth_out);
3183     send_session_ack_message (n);
3184     break;
3185   case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
3186   case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
3187     GNUNET_STATISTICS_update (GST_stats,
3188                               gettext_noop ("# unexpected SYN_ACK messages (not ready)"),
3189                               1,
3190                               GNUNET_NO);
3191     break;
3192   case GNUNET_TRANSPORT_PS_CONNECTED:
3193     /* duplicate SYN_ACK, let's answer by duplicate ACK just in case */
3194     send_session_ack_message (n);
3195     break;
3196   case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
3197     /* we didn't expect any SYN_ACK, as we are waiting for ATS
3198        to give us a new address... */
3199     GNUNET_STATISTICS_update (GST_stats,
3200                               gettext_noop ("# unexpected SYN_ACK messages (waiting on ATS)"),
3201                               1,
3202                               GNUNET_NO);
3203     break;
3204   case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
3205     /* Reconnecting with new address address worked; go back to connected! */
3206     set_state_and_timeout (n,
3207                            GNUNET_TRANSPORT_PS_CONNECTED,
3208                            GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT));
3209     send_session_ack_message (n);
3210     break;
3211   case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
3212     /* new address worked; adopt it and go back to connected! */
3213     set_state_and_timeout (n,
3214                            GNUNET_TRANSPORT_PS_CONNECTED,
3215                            GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT));
3216     GNUNET_break (GNUNET_NO == n->alternative_address.ats_active);
3217
3218     /* Set primary addresses */
3219     set_primary_address (n,
3220                          n->alternative_address.address,
3221                          n->alternative_address.session,
3222                          n->alternative_address.bandwidth_in,
3223                          n->alternative_address.bandwidth_out);
3224     GNUNET_STATISTICS_update (GST_stats,
3225                               gettext_noop ("# Successful attempts to switch addresses"),
3226                               1,
3227                               GNUNET_NO);
3228
3229     GNUNET_HELLO_address_free (n->alternative_address.address);
3230     memset (&n->alternative_address,
3231             0,
3232             sizeof (n->alternative_address));
3233     send_session_ack_message (n);
3234     break;
3235   case GNUNET_TRANSPORT_PS_DISCONNECT:
3236     GNUNET_STATISTICS_update (GST_stats,
3237                               gettext_noop
3238                               ("# unexpected SYN_ACK messages (disconnecting)"),
3239                               1, GNUNET_NO);
3240     return GNUNET_SYSERR;
3241   case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
3242     GNUNET_assert (0);
3243     break;
3244   default:
3245     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3246                 "Unhandled state `%s'\n",
3247                 GNUNET_TRANSPORT_ps2s (n->state));
3248     GNUNET_break (0);
3249     return GNUNET_SYSERR;
3250   }
3251   return GNUNET_OK;
3252 }
3253
3254
3255 /**
3256  * A session was terminated. Take note; if needed, try to get
3257  * an alternative address from ATS.
3258  *
3259  * @param peer identity of the peer where the session died
3260  * @param session session that is gone
3261  * @return #GNUNET_YES if this was a session used, #GNUNET_NO if
3262  *        this session was not in use
3263  */
3264 int
3265 GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer,
3266                                    struct GNUNET_ATS_Session *session)
3267 {
3268   struct NeighbourMapEntry *n;
3269
3270   if (NULL == (n = lookup_neighbour (peer)))
3271     return GNUNET_NO; /* can't affect us */
3272   if (session != n->primary_address.session)
3273   {
3274     /* Free alternative address */
3275     if (session == n->alternative_address.session)
3276     {
3277       if (GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT == n->state)
3278         set_state_and_timeout (n,
3279                                GNUNET_TRANSPORT_PS_CONNECTED,
3280                                n->timeout);
3281       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3282                   "Session died, cleaning up alternative address\n");
3283       free_address (&n->alternative_address);
3284     }
3285     return GNUNET_NO; /* doesn't affect us further */
3286   }
3287
3288   n->expect_latency_response = GNUNET_NO;
3289   /* The session for neighbour's primary address died */
3290   switch (n->state)
3291   {
3292   case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
3293     GNUNET_break (0);
3294     free_neighbour (n);
3295     return GNUNET_YES;
3296   case GNUNET_TRANSPORT_PS_INIT_ATS:
3297     GNUNET_break (0);
3298     free_neighbour (n);
3299     return GNUNET_YES;
3300   case GNUNET_TRANSPORT_PS_SYN_SENT:
3301     /* The session used to send the SYN terminated:
3302      * this implies a connect error*/
3303     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3304                 "Failed to send SYN in CONNECT_SENT with `%s' %p: session terminated\n",
3305                 GST_plugins_a2s (n->primary_address.address),
3306                 n->primary_address.session);
3307
3308     /* Destroy the address since it cannot be used */
3309     unset_primary_address (n);
3310     set_state_and_timeout (n,
3311                            GNUNET_TRANSPORT_PS_INIT_ATS,
3312                            GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT));
3313     break;
3314   case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
3315   case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
3316     /* error on inbound session; free neighbour entirely */
3317     free_neighbour (n);
3318     return GNUNET_YES;
3319   case GNUNET_TRANSPORT_PS_CONNECTED:
3320     /* Our primary connection died, try a fast reconnect */
3321     unset_primary_address (n);
3322     set_state_and_timeout (n,
3323                            GNUNET_TRANSPORT_PS_RECONNECT_ATS,
3324                            GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT));
3325     break;
3326   case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
3327     /* we don't have an address, how can it go down? */
3328     GNUNET_break (0);
3329     break;
3330   case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
3331     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3332                 "Failed to send SYN in RECONNECT_SENT with `%s' %p: session terminated\n",
3333                 GST_plugins_a2s (n->primary_address.address),
3334                 n->primary_address.session);
3335     /* Destroy the address since it cannot be used */
3336     unset_primary_address (n);
3337     set_state_and_timeout (n,
3338                            GNUNET_TRANSPORT_PS_RECONNECT_ATS,
3339                            GNUNET_TIME_relative_to_absolute (ATS_RESPONSE_TIMEOUT));
3340     break;
3341   case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
3342     /* primary went down while we were waiting for SYN_ACK on secondary;
3343        secondary as primary */
3344
3345     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3346                 "Connection `%s' %p to peer `%s' was terminated while switching, "
3347                 "switching to alternative address `%s' %p\n",
3348                 GST_plugins_a2s (n->primary_address.address),
3349                 n->primary_address.session,
3350                 GNUNET_i2s (peer),
3351                 GST_plugins_a2s (n->alternative_address.address),
3352                 n->alternative_address.session);
3353
3354     /* Destroy the inbound address since it cannot be used */
3355     free_address (&n->primary_address);
3356     n->primary_address = n->alternative_address;
3357     GNUNET_assert (GNUNET_YES ==
3358                    GST_ats_is_known (n->primary_address.address,
3359                                      n->primary_address.session));
3360     memset (&n->alternative_address,
3361             0,
3362             sizeof (struct NeighbourAddress));
3363     set_state_and_timeout (n,
3364                            GNUNET_TRANSPORT_PS_RECONNECT_SENT,
3365                            GNUNET_TIME_relative_to_absolute (FAST_RECONNECT_TIMEOUT));
3366     break;
3367   case GNUNET_TRANSPORT_PS_DISCONNECT:
3368     unset_primary_address (n);
3369     break;
3370   case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
3371     /* neighbour was freed and plugins told to terminate session */
3372     return GNUNET_NO;
3373   default:
3374     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3375                 "Unhandled state `%s'\n",
3376                 GNUNET_TRANSPORT_ps2s (n->state));
3377     GNUNET_break (0);
3378     break;
3379   }
3380   if (NULL != n->task)
3381     GNUNET_SCHEDULER_cancel (n->task);
3382   n->task = GNUNET_SCHEDULER_add_now (&master_task, n);
3383   return GNUNET_YES;
3384 }
3385
3386
3387 /**
3388  * We received a 'ACK' message from the other peer.
3389  * If we sent a 'SYN_ACK' last, this means we are now
3390  * connected.  Otherwise, do nothing.
3391  *
3392  * @param message possibly a 'struct GNUNET_ATS_SessionConnectMessage' (check format)
3393  * @param address address of the other peer
3394  * @param session session to use (or NULL)
3395  * @return #GNUNET_OK if the message was fine, #GNUNET_SYSERR on serious error
3396  */
3397 int
3398 GST_neighbours_handle_session_ack (const struct GNUNET_MessageHeader *message,
3399                                    const struct GNUNET_HELLO_Address *address,
3400                                    struct GNUNET_ATS_Session *session)
3401 {
3402   struct NeighbourMapEntry *n;
3403
3404   (void) session;
3405   if (ntohs (message->size) != sizeof (struct GNUNET_MessageHeader))
3406   {
3407     GNUNET_break_op (0);
3408     return GNUNET_SYSERR;
3409   }
3410   GNUNET_STATISTICS_update (GST_stats,
3411                             gettext_noop ("# ACK messages received"),
3412                             1,
3413                             GNUNET_NO);
3414   if (NULL == (n = lookup_neighbour (&address->peer)))
3415   {
3416     GNUNET_break_op (0);
3417     return GNUNET_SYSERR;
3418   }
3419   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3420               "Received ACK for peer `%s' in state %s/%s\n",
3421               GNUNET_i2s (&address->peer),
3422               GNUNET_TRANSPORT_ps2s (n->state),
3423               print_ack_state (n->ack_state));
3424
3425   /* Check if we are in a plausible state for having sent
3426      a SYN_ACK.  If not, return, otherwise break.
3427
3428      The remote peers sends a ACK as a response for a SYN_ACK
3429      message.
3430
3431      We expect a ACK:
3432      - If a remote peer has sent a SYN, we responded with a SYN_ACK and
3433      now wait for the ACK to finally be connected
3434      - If we sent a SYN_ACK to this peer before */
3435
3436   if ( ( (GNUNET_TRANSPORT_PS_SYN_RECV_ACK != n->state) &&
3437          (ACK_SEND_ACK != n->ack_state) ) ||
3438        (NULL == n->primary_address.address) )
3439   {
3440     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3441                 "Received unexpected ACK message from peer `%s' in state %s/%s\n",
3442                 GNUNET_i2s (&address->peer),
3443                 GNUNET_TRANSPORT_ps2s (n->state),
3444                 print_ack_state (n->ack_state));
3445
3446     GNUNET_STATISTICS_update (GST_stats,
3447                               gettext_noop ("# unexpected ACK messages"),
3448                               1,
3449                               GNUNET_NO);
3450     return GNUNET_OK;
3451   }
3452   if (GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT == n->state)
3453   {
3454     /* We tried to switch addresses while being connect. We explicitly wait
3455      * for a SYN_ACK before going to GNUNET_TRANSPORT_PS_CONNECTED,
3456      * so we do not want to set the address as in use! */
3457     return GNUNET_OK;
3458   }
3459   set_state_and_timeout (n,
3460                          GNUNET_TRANSPORT_PS_CONNECTED,
3461                          GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT));
3462
3463   if (NULL == n->primary_address.address) {
3464     /* See issue #3693.
3465      * We are in state = PSY_SYN_RECV_ACK or ack_state = ACK_SEND_ACK, which
3466      * really means we did try (and succeed) to send a SYN and are waiting for
3467      * an ACK.
3468      * That suggests that the primary_address used to be non-NULL, but maybe it
3469      * got reset to NULL without the state being changed appropriately?
3470      */
3471     GNUNET_break (0);
3472     return GNUNET_OK;
3473   }
3474
3475   /* Reset backoff for primary address */
3476   GST_ats_block_reset (n->primary_address.address,
3477                        n->primary_address.session);
3478   return GNUNET_OK;
3479 }
3480
3481
3482 /**
3483  * Test if we're connected to the given peer.
3484  *
3485  * @param target peer to test
3486  * @return #GNUNET_YES if we are connected, #GNUNET_NO if not
3487  */
3488 int
3489 GST_neighbours_test_connected (const struct GNUNET_PeerIdentity *target)
3490 {
3491   return test_connected (lookup_neighbour (target));
3492 }
3493
3494
3495 /**
3496  * Task to asynchronously run #free_neighbour().
3497  *
3498  * @param cls the `struct NeighbourMapEntry` to free
3499  */
3500 static void
3501 delayed_disconnect (void *cls)
3502 {
3503   struct NeighbourMapEntry *n = cls;
3504
3505   n->delayed_disconnect_task = NULL;
3506   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3507               "Disconnecting by request from peer %s\n",
3508               GNUNET_i2s (&n->id));
3509   free_neighbour (n);
3510 }
3511
3512
3513 /**
3514  * We received a quota message from the given peer,
3515  * validate and process.
3516  *
3517  * @param peer sender of the message
3518  * @param msg the quota message
3519  */
3520 void
3521 GST_neighbours_handle_quota_message (const struct GNUNET_PeerIdentity *peer,
3522                                      const struct GNUNET_MessageHeader *msg)
3523 {
3524   struct NeighbourMapEntry *n;
3525   const struct GNUNET_ATS_SessionQuotaMessage *sqm;
3526   struct GNUNET_BANDWIDTH_Value32NBO last;
3527
3528   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3529               "Received QUOTA message from peer `%s'\n",
3530               GNUNET_i2s (peer));
3531   if (ntohs (msg->size) != sizeof (struct GNUNET_ATS_SessionQuotaMessage))
3532   {
3533     GNUNET_break_op (0);
3534     GNUNET_STATISTICS_update (GST_stats,
3535                               gettext_noop ("# quota messages ignored (malformed)"),
3536                               1,
3537                               GNUNET_NO);
3538     return;
3539   }
3540   GNUNET_STATISTICS_update (GST_stats,
3541                             gettext_noop
3542                             ("# QUOTA messages received"),
3543                             1, GNUNET_NO);
3544   sqm = (const struct GNUNET_ATS_SessionQuotaMessage *) msg;
3545   if (NULL == (n = lookup_neighbour (peer)))
3546   {
3547     /* gone already */
3548     return;
3549   }
3550   last = GNUNET_BANDWIDTH_value_max (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3551                                      GNUNET_BANDWIDTH_value_init (ntohl (sqm->quota)));
3552   if (last.value__ != n->neighbour_receive_quota.value__)
3553   {
3554     n->neighbour_receive_quota = last;
3555     send_outbound_quota_to_clients (n);
3556   }
3557 }
3558
3559
3560 /**
3561  * We received a disconnect message from the given peer,
3562  * validate and process.
3563  *
3564  * @param peer sender of the message
3565  * @param msg the disconnect message
3566  */
3567 void
3568 GST_neighbours_handle_disconnect_message (const struct GNUNET_PeerIdentity *peer,
3569                                           const struct GNUNET_MessageHeader *msg)
3570 {
3571   struct NeighbourMapEntry *n;
3572   const struct GNUNET_ATS_SessionDisconnectMessage *sdm;
3573
3574   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3575               "Received DISCONNECT message from peer `%s'\n",
3576               GNUNET_i2s (peer));
3577   if (ntohs (msg->size) != sizeof (struct GNUNET_ATS_SessionDisconnectMessage))
3578   {
3579     GNUNET_break_op (0);
3580     GNUNET_STATISTICS_update (GST_stats,
3581                               gettext_noop
3582                               ("# disconnect messages ignored (malformed)"),
3583                               1,
3584                               GNUNET_NO);
3585     return;
3586   }
3587   GNUNET_STATISTICS_update (GST_stats,
3588                             gettext_noop
3589                             ("# DISCONNECT messages received"),
3590                             1, GNUNET_NO);
3591   sdm = (const struct GNUNET_ATS_SessionDisconnectMessage *) msg;
3592   if (NULL == (n = lookup_neighbour (peer)))
3593   {
3594     /* gone already */
3595     return;
3596   }
3597   if (GNUNET_TIME_absolute_ntoh (sdm->timestamp).abs_value_us <= n->connect_ack_timestamp.abs_value_us)
3598   {
3599     GNUNET_STATISTICS_update (GST_stats,
3600                               gettext_noop ("# disconnect messages ignored (timestamp)"),
3601                               1,
3602                               GNUNET_NO);
3603     return;
3604   }
3605   if (0 != memcmp (peer,
3606                    &sdm->public_key,
3607                    sizeof (struct GNUNET_PeerIdentity)))
3608   {
3609     GNUNET_break_op (0);
3610     return;
3611   }
3612   if (ntohl (sdm->purpose.size) !=
3613       sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
3614       sizeof (struct GNUNET_CRYPTO_EddsaPublicKey) +
3615       sizeof (struct GNUNET_TIME_AbsoluteNBO))
3616   {
3617     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3618                 "DISCONNECT message from peer `%s' has invalid size\n",
3619                 GNUNET_i2s (peer));
3620     GNUNET_break_op (0);
3621     return;
3622   }
3623   if (GNUNET_OK !=
3624       GNUNET_CRYPTO_eddsa_verify (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT,
3625                                   &sdm->purpose,
3626                                   &sdm->signature,
3627                                   &sdm->public_key))
3628   {
3629     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3630                 "DISCONNECT message from peer `%s' cannot be verified \n",
3631                 GNUNET_i2s (peer));
3632     GNUNET_break_op (0);
3633     return;
3634   }
3635   if (NULL == n->delayed_disconnect_task)
3636   {
3637     n->delayed_disconnect_task = GNUNET_SCHEDULER_add_now (&delayed_disconnect,
3638                                                            n);
3639   }
3640 }
3641
3642
3643 /**
3644  * Closure for the #neighbours_iterate() function.
3645  */
3646 struct IteratorContext
3647 {
3648   /**
3649    * Function to call on each connected neighbour.
3650    */
3651   GST_NeighbourIterator cb;
3652
3653   /**
3654    * Closure for @e cb.
3655    */
3656   void *cb_cls;
3657 };
3658
3659
3660 /**
3661  * Call the callback from the closure for each neighbour.
3662  *
3663  * @param cls the `struct IteratorContext`
3664  * @param key the hash of the public key of the neighbour
3665  * @param value the `struct NeighbourMapEntry`
3666  * @return #GNUNET_OK (continue to iterate)
3667  */
3668 static int
3669 neighbours_iterate (void *cls,
3670                     const struct GNUNET_PeerIdentity *key,
3671                     void *value)
3672 {
3673   struct IteratorContext *ic = cls;
3674   struct NeighbourMapEntry *n = value;
3675   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
3676   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
3677
3678   (void) key;
3679   if (NULL != n->primary_address.address)
3680   {
3681     bandwidth_in = n->primary_address.bandwidth_in;
3682     bandwidth_out = n->primary_address.bandwidth_out;
3683   }
3684   else
3685   {
3686     bandwidth_in = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
3687     bandwidth_out = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
3688   }
3689   ic->cb (ic->cb_cls,
3690           &n->id,
3691           n->primary_address.address,
3692           n->state,
3693           n->timeout,
3694           bandwidth_in, bandwidth_out);
3695   return GNUNET_OK;
3696 }
3697
3698
3699 /**
3700  * Iterate over all connected neighbours.
3701  *
3702  * @param cb function to call
3703  * @param cb_cls closure for @a cb
3704  */
3705 void
3706 GST_neighbours_iterate (GST_NeighbourIterator cb,
3707                         void *cb_cls)
3708 {
3709   struct IteratorContext ic;
3710
3711   if (NULL == neighbours)
3712     return; /* can happen during shutdown */
3713   ic.cb = cb;
3714   ic.cb_cls = cb_cls;
3715   GNUNET_CONTAINER_multipeermap_iterate (neighbours,
3716                                          &neighbours_iterate,
3717                                          &ic);
3718 }
3719
3720
3721 /**
3722  * If we have an active connection to the given target, it must be shutdown.
3723  *
3724  * @param target peer to disconnect from
3725  */
3726 void
3727 GST_neighbours_force_disconnect (const struct GNUNET_PeerIdentity *target)
3728 {
3729   struct NeighbourMapEntry *n;
3730
3731   if (NULL == (n = lookup_neighbour (target)))
3732     return;  /* not active */
3733   if (GNUNET_YES == test_connected (n))
3734     GNUNET_STATISTICS_update (GST_stats,
3735                               gettext_noop ("# disconnected from peer upon explicit request"),
3736                               1,
3737                               GNUNET_NO);
3738   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3739               "Forced disconnect from peer %s\n",
3740               GNUNET_i2s (target));
3741   disconnect_neighbour (n);
3742 }
3743
3744
3745 /**
3746  * Obtain current address information for the given neighbour.
3747  *
3748  * @param peer
3749  * @return address currently used
3750  */
3751 const struct GNUNET_HELLO_Address *
3752 GST_neighbour_get_current_address (const struct GNUNET_PeerIdentity *peer)
3753 {
3754   struct NeighbourMapEntry *n;
3755
3756   n = lookup_neighbour (peer);
3757   if (NULL == n)
3758     return NULL;
3759   return n->primary_address.address;
3760 }
3761
3762
3763 /**
3764  * Initialize the neighbours subsystem.
3765  *
3766  * @param max_fds maximum number of fds to use
3767  */
3768 void
3769 GST_neighbours_start (unsigned int max_fds)
3770 {
3771   (void) max_fds;
3772   neighbours = GNUNET_CONTAINER_multipeermap_create (NEIGHBOUR_TABLE_SIZE,
3773                                                      GNUNET_NO);
3774   util_transmission_tk = GNUNET_SCHEDULER_add_delayed (UTIL_TRANSMISSION_INTERVAL,
3775                                                        &utilization_transmission,
3776                                                        NULL);
3777 }
3778
3779
3780 /**
3781  * Disconnect from the given neighbour.
3782  *
3783  * @param cls unused
3784  * @param key hash of neighbour's public key (not used)
3785  * @param value the `struct NeighbourMapEntry` of the neighbour
3786  * @return #GNUNET_OK (continue to iterate)
3787  */
3788 static int
3789 disconnect_all_neighbours (void *cls,
3790                            const struct GNUNET_PeerIdentity *key,
3791                            void *value)
3792 {
3793   struct NeighbourMapEntry *n = value;
3794
3795   (void) cls;
3796   (void) key;
3797   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3798               "Disconnecting peer `%4s' during shutdown\n",
3799               GNUNET_i2s (&n->id));
3800   free_neighbour (n);
3801   return GNUNET_OK;
3802 }
3803
3804
3805 /**
3806  * Cleanup the neighbours subsystem.
3807  */
3808 void
3809 GST_neighbours_stop ()
3810 {
3811   if (NULL == neighbours)
3812     return;
3813   if (NULL != util_transmission_tk)
3814   {
3815     GNUNET_SCHEDULER_cancel (util_transmission_tk);
3816     util_transmission_tk = NULL;
3817   }
3818   GNUNET_CONTAINER_multipeermap_iterate (neighbours,
3819                                          &disconnect_all_neighbours,
3820                                          NULL);
3821   GNUNET_CONTAINER_multipeermap_destroy (neighbours);
3822   neighbours = NULL;
3823 }
3824
3825
3826 /* end of file gnunet-service-transport_neighbours.c */