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