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