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