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