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