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