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