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