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