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