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