-cleaner
[oweals/gnunet.git] / src / transport / gnunet-service-transport_neighbours.c
1 /*
2      This file is part of GNUnet.
3      (C) 2010,2011 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  * Size of the neighbour hash map.
41  */
42 #define NEIGHBOUR_TABLE_SIZE 256
43
44 /**
45  * How often must a peer violate bandwidth quotas before we start
46  * to simply drop its messages?
47  */
48 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
49
50 /**
51  * How often do we send KEEPALIVE messages to each of our neighbours and measure
52  * the latency with this neighbour?
53  * (idle timeout is 5 minutes or 300 seconds, so with 30s interval we
54  * send 10 keepalives in each interval, so 10 messages would need to be
55  * lost in a row for a disconnect).
56  */
57 #define KEEPALIVE_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
58
59
60 #define ATS_RESPONSE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
61
62 #define FAST_RECONNECT_RATE GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100)
63
64 #define FAST_RECONNECT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
65
66 #define SETUP_CONNECTION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
67
68 /**
69  * Entry in neighbours.
70  */
71 struct NeighbourMapEntry;
72
73 GNUNET_NETWORK_STRUCT_BEGIN
74
75 /**
76  * Message a peer sends to another to indicate its
77  * preference for communicating via a particular
78  * session (and the desire to establish a real
79  * connection).
80  */
81 struct SessionConnectMessage
82 {
83   /**
84    * Header of type 'GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT'
85    */
86   struct GNUNET_MessageHeader header;
87
88   /**
89    * Always zero.
90    */
91   uint32_t reserved GNUNET_PACKED;
92
93   /**
94    * Absolute time at the sender.  Only the most recent connect
95    * message implies which session is preferred by the sender.
96    */
97   struct GNUNET_TIME_AbsoluteNBO timestamp;
98
99 };
100
101
102 struct SessionDisconnectMessage
103 {
104   /**
105    * Header of type 'GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT'
106    */
107   struct GNUNET_MessageHeader header;
108
109   /**
110    * Always zero.
111    */
112   uint32_t reserved GNUNET_PACKED;
113
114   /**
115    * Purpose of the signature.  Extends over the timestamp.
116    * Purpose should be GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DISCONNECT.
117    */
118   struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
119
120   /**
121    * Absolute time at the sender.  Only the most recent connect
122    * message implies which session is preferred by the sender.
123    */
124   struct GNUNET_TIME_AbsoluteNBO timestamp;
125
126   /**
127    * Public key of the sender.
128    */
129   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
130
131   /**
132    * Signature of the peer that sends us the disconnect.  Only
133    * valid if the timestamp is AFTER the timestamp from the
134    * corresponding 'CONNECT' message.
135    */
136   struct GNUNET_CRYPTO_RsaSignature signature;
137
138 };
139 GNUNET_NETWORK_STRUCT_END
140
141 /**
142  * For each neighbour we keep a list of messages
143  * that we still want to transmit to the neighbour.
144  */
145 struct MessageQueue
146 {
147
148   /**
149    * This is a doubly linked list.
150    */
151   struct MessageQueue *next;
152
153   /**
154    * This is a doubly linked list.
155    */
156   struct MessageQueue *prev;
157
158   /**
159    * Once this message is actively being transmitted, which
160    * neighbour is it associated with?
161    */
162   struct NeighbourMapEntry *n;
163
164   /**
165    * Function to call once we're done.
166    */
167   GST_NeighbourSendContinuation cont;
168
169   /**
170    * Closure for 'cont'
171    */
172   void *cont_cls;
173
174   /**
175    * The message(s) we want to transmit, GNUNET_MessageHeader(s)
176    * stuck together in memory.  Allocated at the end of this struct.
177    */
178   const char *message_buf;
179
180   /**
181    * Size of the message buf
182    */
183   size_t message_buf_size;
184
185   /**
186    * At what time should we fail?
187    */
188   struct GNUNET_TIME_Absolute timeout;
189
190 };
191
192
193 enum State
194 {
195   /**
196    * fresh peer or completely disconnected
197    */
198   S_NOT_CONNECTED,
199
200   /**
201    * sent CONNECT message to other peer, waiting for CONNECT_ACK
202    */
203   S_CONNECT_SENT,
204
205   /**
206    * received CONNECT message to other peer, sending CONNECT_ACK
207    */
208   S_CONNECT_RECV,
209
210   /**
211    * received ACK or payload
212    */
213   S_CONNECTED,
214
215   /**
216    * connection ended, fast reconnect
217    */
218   S_FAST_RECONNECT,
219
220   /**
221    * Disconnect in progress
222    */
223   S_DISCONNECT
224 };
225
226 enum Address_State
227 {
228   USED,
229   UNUSED,
230   FRESH,
231 };
232
233
234 /**
235  * Entry in neighbours.
236  */
237 struct NeighbourMapEntry
238 {
239
240   /**
241    * Head of list of messages we would like to send to this peer;
242    * must contain at most one message per client.
243    */
244   struct MessageQueue *messages_head;
245
246   /**
247    * Tail of list of messages we would like to send to this peer; must
248    * contain at most one message per client.
249    */
250   struct MessageQueue *messages_tail;
251
252   /**
253    * Are we currently trying to send a message? If so, which one?
254    */
255   struct MessageQueue *is_active;
256
257   /**
258    * Active session for communicating with the peer.
259    */
260   struct Session *session;
261
262   /**
263    * Address we currently use.
264    */
265   struct GNUNET_HELLO_Address *address;
266
267   /**
268    * Address we currently use.
269    */
270   struct GNUNET_HELLO_Address *fast_reconnect_address;
271
272
273   /**
274    * Identity of this neighbour.
275    */
276   struct GNUNET_PeerIdentity id;
277
278   /**
279    * ID of task scheduled to run when this peer is about to
280    * time out (will free resources associated with the peer).
281    */
282   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
283
284   /**
285    * ID of task scheduled to send keepalives.
286    */
287   GNUNET_SCHEDULER_TaskIdentifier keepalive_task;
288
289   /**
290    * ID of task scheduled to run when we should try transmitting
291    * the head of the message queue.
292    */
293   GNUNET_SCHEDULER_TaskIdentifier transmission_task;
294
295   /**
296    * Tracker for inbound bandwidth.
297    */
298   struct GNUNET_BANDWIDTH_Tracker in_tracker;
299
300   /**
301    * Inbound bandwidth from ATS, activated when connection is up
302    */
303   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
304
305   /**
306    * Inbound bandwidth from ATS, activated when connection is up
307    */
308   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
309
310   /**
311    * Timestamp of the 'SESSION_CONNECT' message we got from the other peer
312    */
313   struct GNUNET_TIME_Absolute connect_ts;
314
315   /**
316    * When did we sent the last keep-alive message?
317    */
318   struct GNUNET_TIME_Absolute keep_alive_sent;
319
320   /**
321    * Latest calculated latency value
322    */
323   struct GNUNET_TIME_Relative latency;
324
325   /**
326    * Timeout for ATS
327    * We asked ATS for a new address for this peer
328    */
329   GNUNET_SCHEDULER_TaskIdentifier ats_suggest;
330
331   /**
332    * Delay for ATS request
333    */
334   GNUNET_SCHEDULER_TaskIdentifier ats_request;
335
336   /**
337    * Task the resets the peer state after due to an pending
338    * unsuccessful connection setup
339    */
340   GNUNET_SCHEDULER_TaskIdentifier state_reset;
341
342
343   /**
344    * How often has the other peer (recently) violated the inbound
345    * traffic limit?  Incremented by 10 per violation, decremented by 1
346    * per non-violation (for each time interval).
347    */
348   unsigned int quota_violation_count;
349
350
351   /**
352    * The current state of the peer
353    * Element of enum State
354    */
355   int state;
356
357   /**
358    * Did we sent an KEEP_ALIVE message and are we expecting a response?
359    */
360   int expect_latency_response;
361
362   /**
363    * Was the address used successfully
364    */
365   int address_state;
366
367   /**
368    * Fast reconnect attempts for identical address
369    */
370   unsigned int fast_reconnect_attempts;
371 };
372
373
374 /**
375  * All known neighbours and their HELLOs.
376  */
377 static struct GNUNET_CONTAINER_MultiHashMap *neighbours;
378
379 /**
380  * Closure for connect_notify_cb, disconnect_notify_cb and address_change_cb
381  */
382 static void *callback_cls;
383
384 /**
385  * Function to call when we connected to a neighbour.
386  */
387 static GNUNET_TRANSPORT_NotifyConnect connect_notify_cb;
388
389 /**
390  * Function to call when we disconnected from a neighbour.
391  */
392 static GNUNET_TRANSPORT_NotifyDisconnect disconnect_notify_cb;
393
394 /**
395  * Function to call when we changed an active address of a neighbour.
396  */
397 static GNUNET_TRANSPORT_PeerIterateCallback address_change_cb;
398
399 /**
400  * counter for connected neighbours
401  */
402 static int neighbours_connected;
403
404 /**
405  * Lookup a neighbour entry in the neighbours hash map.
406  *
407  * @param pid identity of the peer to look up
408  * @return the entry, NULL if there is no existing record
409  */
410 static struct NeighbourMapEntry *
411 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
412 {
413   return GNUNET_CONTAINER_multihashmap_get (neighbours, &pid->hashPubKey);
414 }
415
416 /**
417  * Disconnect from the given neighbour, clean up the record.
418  *
419  * @param n neighbour to disconnect from
420  */
421 static void
422 disconnect_neighbour (struct NeighbourMapEntry *n);
423
424 #define change_state(n, state, ...) change (n, state, __LINE__)
425
426 static int
427 is_connecting (struct NeighbourMapEntry *n)
428 {
429   if ((n->state > S_NOT_CONNECTED) && (n->state < S_CONNECTED))
430     return GNUNET_YES;
431   return GNUNET_NO;
432 }
433
434 static int
435 is_connected (struct NeighbourMapEntry *n)
436 {
437   if (n->state == S_CONNECTED)
438     return GNUNET_YES;
439   return GNUNET_NO;
440 }
441
442 static int
443 is_disconnecting (struct NeighbourMapEntry *n)
444 {
445   if (n->state == S_DISCONNECT)
446     return GNUNET_YES;
447   return GNUNET_NO;
448 }
449
450 static const char *
451 print_state (int state)
452 {
453   switch (state)
454   {
455   case S_CONNECTED:
456     return "S_CONNECTED";
457     break;
458   case S_CONNECT_RECV:
459     return "S_CONNECT_RECV";
460     break;
461   case S_CONNECT_SENT:
462     return "S_CONNECT_SENT";
463     break;
464   case S_DISCONNECT:
465     return "S_DISCONNECT";
466     break;
467   case S_NOT_CONNECTED:
468     return "S_NOT_CONNECTED";
469     break;
470   case S_FAST_RECONNECT:
471     return "S_FAST_RECONNECT";
472     break;
473   default:
474     GNUNET_break (0);
475     break;
476   }
477   return NULL;
478 }
479
480 static int
481 change (struct NeighbourMapEntry *n, int state, int line);
482
483 static void
484 ats_suggest_cancel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
485
486
487 static void
488 reset_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
489 {
490   struct NeighbourMapEntry *n = cls;
491
492   if (n == NULL)
493     return;
494
495   n->state_reset = GNUNET_SCHEDULER_NO_TASK;
496   if (n->state == S_CONNECTED)
497     return;
498
499 #if DEBUG_TRANSPORT
500   GNUNET_STATISTICS_update (GST_stats,
501                             gettext_noop
502                             ("# failed connection attempts due to timeout"), 1,
503                             GNUNET_NO);
504 #endif
505
506   /* resetting state */
507
508   if (n->state == S_FAST_RECONNECT)
509   {
510     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
511                 "Fast reconnect time out, disconnecting peer `%s'\n",
512                 GNUNET_i2s (&n->id));
513     disconnect_neighbour(n);
514     return;
515   }
516
517   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
518               "State for neighbour `%s' %X changed from `%s' to `%s' in line %u\n",
519               GNUNET_i2s (&n->id), n, print_state(n->state), "S_NOT_CONNECTED", __LINE__);
520
521   n->state = S_NOT_CONNECTED;
522
523   /* destroying address */
524   if (n->address != NULL)
525   {
526     GNUNET_assert (strlen (n->address->transport_name) > 0);
527     GNUNET_ATS_address_destroyed (GST_ats, n->address, n->session);
528   }
529
530   /* request new address */
531   if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
532     GNUNET_SCHEDULER_cancel (n->ats_suggest);
533   n->ats_suggest =
534       GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel,
535                                     n);
536   GNUNET_ATS_suggest_address (GST_ats, &n->id);
537 }
538
539 static int
540 change (struct NeighbourMapEntry *n, int state, int line)
541 {
542   int previous_state;
543   /* allowed transitions */
544   int allowed = GNUNET_NO;
545
546   previous_state = n->state;
547
548   switch (n->state)
549   {
550   case S_NOT_CONNECTED:
551     if ((state == S_CONNECT_RECV) || (state == S_CONNECT_SENT) ||
552         (state == S_DISCONNECT))
553       allowed = GNUNET_YES;
554     break;
555   case S_CONNECT_RECV:
556     allowed = GNUNET_YES;
557     break;
558   case S_CONNECT_SENT:
559     allowed = GNUNET_YES;
560     break;
561   case S_CONNECTED:
562     if ((state == S_DISCONNECT) || (state == S_FAST_RECONNECT))
563       allowed = GNUNET_YES;
564     break;
565   case S_DISCONNECT:
566     break;
567   case S_FAST_RECONNECT:
568     if ((state == S_CONNECTED) || (state == S_DISCONNECT))
569       allowed = GNUNET_YES;
570     break;
571   default:
572     GNUNET_break (0);
573     break;
574   }
575   if (allowed == GNUNET_NO)
576   {
577     char *old = GNUNET_strdup (print_state (n->state));
578     char *new = GNUNET_strdup (print_state (state));
579
580     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
581                 "Illegal state transition from `%s' to `%s' in line %u \n", old,
582                 new, line);
583     GNUNET_break (0);
584     GNUNET_free (old);
585     GNUNET_free (new);
586     return GNUNET_SYSERR;
587   }
588   {
589     char *old = GNUNET_strdup (print_state (n->state));
590     char *new = GNUNET_strdup (print_state (state));
591
592     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
593                 "State for neighbour `%s' %X changed from `%s' to `%s' in line %u\n",
594                 GNUNET_i2s (&n->id), n, old, new, line);
595     GNUNET_free (old);
596     GNUNET_free (new);
597   }
598   n->state = state;
599
600   switch (n->state)
601   {
602   case S_FAST_RECONNECT:
603   case S_CONNECT_RECV:
604   case S_CONNECT_SENT:
605     if (n->state_reset != GNUNET_SCHEDULER_NO_TASK)
606       GNUNET_SCHEDULER_cancel (n->state_reset);
607     n->state_reset =
608         GNUNET_SCHEDULER_add_delayed (SETUP_CONNECTION_TIMEOUT, &reset_task, n);
609     break;
610   case S_CONNECTED:
611   case S_NOT_CONNECTED:
612   case S_DISCONNECT:
613     if (GNUNET_SCHEDULER_NO_TASK != n->state_reset)
614     {
615 #if DEBUG_TRANSPORT
616       char *old = GNUNET_strdup (print_state (n->state));
617       char *new = GNUNET_strdup (print_state (state));
618
619       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
620                   "Removed reset task for peer `%s' %s failed in state transition `%s' -> `%s' \n",
621                   GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), old, new);
622       GNUNET_free (old);
623       GNUNET_free (new);
624 #endif
625       GNUNET_assert (n->state_reset != GNUNET_SCHEDULER_NO_TASK);
626       GNUNET_SCHEDULER_cancel (n->state_reset);
627       n->state_reset = GNUNET_SCHEDULER_NO_TASK;
628     }
629     break;
630
631   default:
632     GNUNET_assert (0);
633   }
634
635   if (NULL != address_change_cb)
636   {
637     if (n->state == S_CONNECTED)
638       address_change_cb (callback_cls, &n->id, n->address);
639     else if (previous_state == S_CONNECTED)
640       address_change_cb (callback_cls, &n->id, NULL);
641   }
642
643   return GNUNET_OK;
644 }
645
646 static ssize_t
647 send_with_session (struct NeighbourMapEntry *n,
648                    const char *msgbuf, size_t msgbuf_size,
649                    uint32_t priority,
650                    struct GNUNET_TIME_Relative timeout,
651                    GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
652 {
653   struct GNUNET_TRANSPORT_PluginFunctions *papi;
654   size_t ret = GNUNET_SYSERR;
655
656   GNUNET_assert (n != NULL);
657   GNUNET_assert (n->session != NULL);
658
659   papi = GST_plugins_find (n->address->transport_name);
660   if (papi == NULL)
661   {
662     if (cont != NULL)
663       cont (cont_cls, &n->id, GNUNET_SYSERR);
664     return GNUNET_SYSERR;
665   }
666
667   ret = papi->send (papi->cls,
668                    n->session,
669                    msgbuf, msgbuf_size,
670                    0,
671                    timeout,
672                    cont, cont_cls);
673
674   if ((ret == -1) && (cont != NULL))
675       cont (cont_cls, &n->id, GNUNET_SYSERR);
676   return ret;
677 }
678
679 /**
680  * Task invoked to start a transmission to another peer.
681  *
682  * @param cls the 'struct NeighbourMapEntry'
683  * @param tc scheduler context
684  */
685 static void
686 transmission_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
687
688
689 /**
690  * We're done with our transmission attempt, continue processing.
691  *
692  * @param cls the 'struct MessageQueue' of the message
693  * @param receiver intended receiver
694  * @param success whether it worked or not
695  */
696 static void
697 transmit_send_continuation (void *cls,
698                             const struct GNUNET_PeerIdentity *receiver,
699                             int success)
700 {
701   struct MessageQueue *mq = cls;
702   struct NeighbourMapEntry *n;
703   struct NeighbourMapEntry *tmp;
704
705   tmp = lookup_neighbour (receiver);
706   n = mq->n;
707   if ((NULL != n) && (tmp != NULL) && (tmp == n))
708   {
709     GNUNET_assert (n->is_active == mq);
710     n->is_active = NULL;
711     if (success == GNUNET_YES)
712     {
713       GNUNET_assert (n->transmission_task == GNUNET_SCHEDULER_NO_TASK);
714       n->transmission_task = GNUNET_SCHEDULER_add_now (&transmission_task, n);
715     }
716   }
717 #if DEBUG_TRANSPORT
718   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message of type %u was %s\n",
719               ntohs (((struct GNUNET_MessageHeader *) mq->message_buf)->type),
720               (success == GNUNET_OK) ? "successful" : "FAILED");
721 #endif
722   if (NULL != mq->cont)
723     mq->cont (mq->cont_cls, success);
724   GNUNET_free (mq);
725 }
726
727
728 /**
729  * Check the ready list for the given neighbour and if a plugin is
730  * ready for transmission (and if we have a message), do so!
731  *
732  * @param n target peer for which to transmit
733  */
734 static void
735 try_transmission_to_peer (struct NeighbourMapEntry *n)
736 {
737   struct MessageQueue *mq;
738   struct GNUNET_TIME_Relative timeout;
739   ssize_t ret;
740
741   if (n->is_active != NULL)
742   {
743     GNUNET_break (0);
744     return;                     /* transmission already pending */
745   }
746   if (n->transmission_task != GNUNET_SCHEDULER_NO_TASK)
747   {
748     GNUNET_break (0);
749     return;                     /* currently waiting for bandwidth */
750   }
751   while (NULL != (mq = n->messages_head))
752   {
753     timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
754     if (timeout.rel_value > 0)
755       break;
756     GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
757     n->is_active = mq;
758     mq->n = n;
759     transmit_send_continuation (mq, &n->id, GNUNET_SYSERR);     /* timeout */
760   }
761   if (NULL == mq)
762     return;                     /* no more messages */
763
764   if (n->address == NULL)
765   {
766 #if DEBUG_TRANSPORT
767     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No address for peer `%s'\n",
768                 GNUNET_i2s (&n->id));
769 #endif
770     GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
771     transmit_send_continuation (mq, &n->id, GNUNET_SYSERR);
772     GNUNET_assert (n->transmission_task == GNUNET_SCHEDULER_NO_TASK);
773     n->transmission_task = GNUNET_SCHEDULER_add_now (&transmission_task, n);
774     return;
775   }
776
777   if (GST_plugins_find (n->address->transport_name) == NULL)
778   {
779     GNUNET_break (0);
780     return;
781   }
782   GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
783   n->is_active = mq;
784   mq->n = n;
785
786   if ((n->address->address_length == 0) && (n->session == NULL))
787   {
788     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No address for peer `%s'\n",
789                 GNUNET_i2s (&n->id));
790     transmit_send_continuation (mq, &n->id, GNUNET_SYSERR);
791     GNUNET_assert (n->transmission_task == GNUNET_SCHEDULER_NO_TASK);
792     n->transmission_task = GNUNET_SCHEDULER_add_now (&transmission_task, n);
793     return;
794   }
795
796   ret = send_with_session(n,
797               mq->message_buf, mq->message_buf_size,
798               0, timeout,
799               &transmit_send_continuation, mq);
800
801   if (ret == -1)
802   {
803     /* failure, but 'send' would not call continuation in this case,
804      * so we need to do it here! */
805     transmit_send_continuation (mq, &n->id, GNUNET_SYSERR);
806   }
807
808 }
809
810
811 /**
812  * Task invoked to start a transmission to another peer.
813  *
814  * @param cls the 'struct NeighbourMapEntry'
815  * @param tc scheduler context
816  */
817 static void
818 transmission_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
819 {
820   struct NeighbourMapEntry *n = cls;
821
822   GNUNET_assert (NULL != lookup_neighbour (&n->id));
823   n->transmission_task = GNUNET_SCHEDULER_NO_TASK;
824   try_transmission_to_peer (n);
825 }
826
827
828 /**
829  * Initialize the neighbours subsystem.
830  *
831  * @param cls closure for callbacks
832  * @param connect_cb function to call if we connect to a peer
833  * @param disconnect_cb function to call if we disconnect from a peer
834  * @param peer_address_cb function to call if we change an active address
835  *                   of a neighbour
836  */
837 void
838 GST_neighbours_start (void *cls,
839                       GNUNET_TRANSPORT_NotifyConnect connect_cb,
840                       GNUNET_TRANSPORT_NotifyDisconnect disconnect_cb,
841                       GNUNET_TRANSPORT_PeerIterateCallback peer_address_cb)
842 {
843   callback_cls = cls;
844   connect_notify_cb = connect_cb;
845   disconnect_notify_cb = disconnect_cb;
846   address_change_cb = peer_address_cb;
847   neighbours = GNUNET_CONTAINER_multihashmap_create (NEIGHBOUR_TABLE_SIZE);
848 }
849
850
851 static void
852 send_disconnect_cont (void *cls, const struct GNUNET_PeerIdentity *target,
853                       int result)
854 {
855 #if DEBUG_TRANSPORT
856   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
857               "Sending DISCONNECT message to peer `%4s': %i\n",
858               GNUNET_i2s (target), result);
859 #endif
860 }
861
862
863 static int
864 send_disconnect (struct NeighbourMapEntry * n)
865 {
866   size_t ret;
867   struct SessionDisconnectMessage disconnect_msg;
868
869 #if DEBUG_TRANSPORT
870   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
871               "Sending DISCONNECT message to peer `%4s'\n",
872               GNUNET_i2s (&n->id));
873 #endif
874
875   disconnect_msg.header.size = htons (sizeof (struct SessionDisconnectMessage));
876   disconnect_msg.header.type =
877       htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT);
878   disconnect_msg.reserved = htonl (0);
879   disconnect_msg.purpose.size =
880       htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
881              sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) +
882              sizeof (struct GNUNET_TIME_AbsoluteNBO));
883   disconnect_msg.purpose.purpose =
884       htonl (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT);
885   disconnect_msg.timestamp =
886       GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
887   disconnect_msg.public_key = GST_my_public_key;
888   GNUNET_assert (GNUNET_OK ==
889                  GNUNET_CRYPTO_rsa_sign (GST_my_private_key,
890                                          &disconnect_msg.purpose,
891                                          &disconnect_msg.signature));
892
893   ret = send_with_session (n,
894             (const char *) &disconnect_msg, sizeof (disconnect_msg),
895             UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL,
896             &send_disconnect_cont, NULL);
897
898   if (ret == GNUNET_SYSERR)
899     return GNUNET_SYSERR;
900
901   GNUNET_STATISTICS_update (GST_stats,
902                             gettext_noop
903                             ("# peers disconnected due to external request"), 1,
904                             GNUNET_NO);
905   return GNUNET_OK;
906 }
907
908
909 /**
910  * Disconnect from the given neighbour, clean up the record.
911  *
912  * @param n neighbour to disconnect from
913  */
914 static void
915 disconnect_neighbour (struct NeighbourMapEntry *n)
916 {
917   struct MessageQueue *mq;
918   int previous_state;
919
920   previous_state = n->state;
921
922   if (is_disconnecting (n))
923     return;
924
925   /* send DISCONNECT MESSAGE */
926   if (previous_state == S_CONNECTED)
927   {
928     if (GNUNET_OK == send_disconnect (n))
929       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent DISCONNECT_MSG to `%s'\n",
930                   GNUNET_i2s (&n->id));
931     else
932       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
933                   "Could not send DISCONNECT_MSG to `%s'\n",
934                   GNUNET_i2s (&n->id));
935   }
936
937   change_state (n, S_DISCONNECT);
938
939   if (previous_state == S_CONNECTED)
940   {
941     GNUNET_assert (NULL != n->address);
942     if (n->address_state == USED)
943     {
944       GST_validation_set_address_use (n->address, n->session, GNUNET_NO, __LINE__);
945       GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_NO);
946       n->address_state = UNUSED;
947     }
948   }
949
950   if (n->address != NULL)
951   {
952     struct GNUNET_TRANSPORT_PluginFunctions *papi;
953
954     papi = GST_plugins_find (n->address->transport_name);
955     if (papi != NULL)
956       papi->disconnect (papi->cls, &n->id);
957   }
958   while (NULL != (mq = n->messages_head))
959   {
960     GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
961     if (NULL != mq->cont)
962       mq->cont (mq->cont_cls, GNUNET_SYSERR);
963     GNUNET_free (mq);
964   }
965   if (NULL != n->is_active)
966   {
967     n->is_active->n = NULL;
968     n->is_active = NULL;
969   }
970
971   switch (previous_state)
972   {
973   case S_CONNECTED:
974     GNUNET_assert (neighbours_connected > 0);
975     neighbours_connected--;
976     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != n->keepalive_task);
977     GNUNET_SCHEDULER_cancel (n->keepalive_task);
978     n->keepalive_task = GNUNET_SCHEDULER_NO_TASK;
979     n->expect_latency_response = GNUNET_NO;
980     GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), -1,
981                               GNUNET_NO);
982     disconnect_notify_cb (callback_cls, &n->id);
983     break;
984   case S_FAST_RECONNECT:
985     GNUNET_STATISTICS_update (GST_stats,
986                               gettext_noop ("# fast reconnects failed"), 1,
987                               GNUNET_NO);
988     disconnect_notify_cb (callback_cls, &n->id);
989     break;
990   default:
991     break;
992   }
993
994   GNUNET_ATS_suggest_address_cancel (GST_ats, &n->id);
995
996   GNUNET_assert (GNUNET_YES ==
997                  GNUNET_CONTAINER_multihashmap_remove (neighbours,
998                                                        &n->id.hashPubKey, n));
999   if (GNUNET_SCHEDULER_NO_TASK != n->ats_suggest)
1000   {
1001     GNUNET_SCHEDULER_cancel (n->ats_suggest);
1002     n->ats_suggest = GNUNET_SCHEDULER_NO_TASK;
1003   }
1004   if (n->ats_request != GNUNET_SCHEDULER_NO_TASK)
1005   {
1006     GNUNET_SCHEDULER_cancel (n->ats_request);
1007     n->ats_request = GNUNET_SCHEDULER_NO_TASK;
1008   }
1009
1010   if (GNUNET_SCHEDULER_NO_TASK != n->timeout_task)
1011   {
1012     GNUNET_SCHEDULER_cancel (n->timeout_task);
1013     n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1014   }
1015   if (GNUNET_SCHEDULER_NO_TASK != n->transmission_task)
1016   {
1017     GNUNET_SCHEDULER_cancel (n->transmission_task);
1018     n->transmission_task = GNUNET_SCHEDULER_NO_TASK;
1019   }
1020   if (NULL != n->fast_reconnect_address)
1021   {
1022     GNUNET_HELLO_address_free (n->fast_reconnect_address);
1023     n->fast_reconnect_address = NULL;
1024   }
1025   if (NULL != n->address)
1026   {
1027     GNUNET_HELLO_address_free (n->address);
1028     n->address = NULL;
1029   }
1030   n->session = NULL;
1031   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting peer `%4s', %X\n",
1032               GNUNET_i2s (&n->id), n);
1033   GNUNET_free (n);
1034 }
1035
1036
1037 /**
1038  * Peer has been idle for too long. Disconnect.
1039  *
1040  * @param cls the 'struct NeighbourMapEntry' of the neighbour that went idle
1041  * @param tc scheduler context
1042  */
1043 static void
1044 neighbour_timeout_task (void *cls,
1045                         const struct GNUNET_SCHEDULER_TaskContext *tc)
1046 {
1047   struct NeighbourMapEntry *n = cls;
1048
1049   n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1050   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer`%4s' disconnected due to timeout\n",
1051               GNUNET_i2s (&n->id));
1052
1053   GNUNET_STATISTICS_update (GST_stats,
1054                             gettext_noop
1055                             ("# peers disconnected due to timeout"), 1,
1056                             GNUNET_NO);
1057   disconnect_neighbour (n);
1058 }
1059
1060
1061 /**
1062  * Send another keepalive message.
1063  *
1064  * @param cls the 'struct NeighbourMapEntry' of the neighbour that went idle
1065  * @param tc scheduler context
1066  */
1067 static void
1068 neighbour_keepalive_task (void *cls,
1069                           const struct GNUNET_SCHEDULER_TaskContext *tc)
1070 {
1071   struct NeighbourMapEntry *n = cls;
1072   struct GNUNET_MessageHeader m;
1073   int ret;
1074
1075   GNUNET_assert (S_CONNECTED == n->state);
1076   n->keepalive_task =
1077       GNUNET_SCHEDULER_add_delayed (KEEPALIVE_FREQUENCY,
1078                                     &neighbour_keepalive_task, n);
1079
1080   GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# keepalives sent"), 1,
1081                             GNUNET_NO);
1082   m.size = htons (sizeof (struct GNUNET_MessageHeader));
1083   m.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE);
1084
1085   ret = send_with_session (n,
1086             (const void *) &m, sizeof (m),
1087             UINT32_MAX /* priority */ ,
1088             GNUNET_TIME_UNIT_FOREVER_REL,
1089             NULL, NULL);
1090
1091   n->expect_latency_response = GNUNET_NO;
1092   n->keep_alive_sent = GNUNET_TIME_absolute_get_zero ();
1093   if (ret != GNUNET_SYSERR)
1094   {
1095     n->expect_latency_response = GNUNET_YES;
1096     n->keep_alive_sent = GNUNET_TIME_absolute_get ();
1097   }
1098
1099 }
1100
1101
1102 /**
1103  * Disconnect from the given neighbour.
1104  *
1105  * @param cls unused
1106  * @param key hash of neighbour's public key (not used)
1107  * @param value the 'struct NeighbourMapEntry' of the neighbour
1108  */
1109 static int
1110 disconnect_all_neighbours (void *cls, const GNUNET_HashCode * key, void *value)
1111 {
1112   struct NeighbourMapEntry *n = value;
1113
1114 #if DEBUG_TRANSPORT
1115   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s', %s\n",
1116               GNUNET_i2s (&n->id), "SHUTDOWN_TASK");
1117 #endif
1118   if (S_CONNECTED == n->state)
1119     GNUNET_STATISTICS_update (GST_stats,
1120                               gettext_noop
1121                               ("# peers disconnected due to global disconnect"),
1122                               1, GNUNET_NO);
1123   disconnect_neighbour (n);
1124   return GNUNET_OK;
1125 }
1126
1127
1128 static void
1129 ats_suggest_cancel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1130 {
1131   struct NeighbourMapEntry *n = cls;
1132
1133   n->ats_suggest = GNUNET_SCHEDULER_NO_TASK;
1134
1135   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1136               "ATS did not suggested address to connect to peer `%s'\n",
1137               GNUNET_i2s (&n->id));
1138
1139   GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# ATS address suggestions failed"), 1,
1140                             GNUNET_NO);
1141
1142
1143   disconnect_neighbour (n);
1144 }
1145
1146 /**
1147  * Cleanup the neighbours subsystem.
1148  */
1149 void
1150 GST_neighbours_stop ()
1151 {
1152   // This can happen during shutdown
1153   if (neighbours == NULL)
1154   {
1155     return;
1156   }
1157
1158   GNUNET_CONTAINER_multihashmap_iterate (neighbours, &disconnect_all_neighbours,
1159                                          NULL);
1160   GNUNET_CONTAINER_multihashmap_destroy (neighbours);
1161 //  GNUNET_assert (neighbours_connected == 0);
1162   neighbours = NULL;
1163   callback_cls = NULL;
1164   connect_notify_cb = NULL;
1165   disconnect_notify_cb = NULL;
1166   address_change_cb = NULL;
1167 }
1168
1169 struct ContinutionContext
1170 {
1171   struct GNUNET_HELLO_Address *address;
1172
1173   struct Session *session;
1174 };
1175
1176 static void
1177 send_outbound_quota (const struct GNUNET_PeerIdentity *target,
1178                      struct GNUNET_BANDWIDTH_Value32NBO quota)
1179 {
1180   struct QuotaSetMessage q_msg;
1181
1182 #if DEBUG_TRANSPORT
1183   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1184               "Sending outbound quota of %u Bps for peer `%s' to all clients\n",
1185               ntohl (quota.value__), GNUNET_i2s (target));
1186 #endif
1187   q_msg.header.size = htons (sizeof (struct QuotaSetMessage));
1188   q_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA);
1189   q_msg.quota = quota;
1190   q_msg.peer = (*target);
1191   GST_clients_broadcast (&q_msg.header, GNUNET_NO);
1192 }
1193
1194 /**
1195  * We tried to send a SESSION_CONNECT message to another peer.  If this
1196  * succeeded, we change the state.  If it failed, we should tell
1197  * ATS to not use this address anymore (until it is re-validated).
1198  *
1199  * @param cls the 'struct GNUNET_HELLO_Address' of the address that was tried
1200  * @param target peer to send the message to
1201  * @param success GNUNET_OK on success
1202  */
1203 static void
1204 send_connect_continuation (void *cls, const struct GNUNET_PeerIdentity *target,
1205                            int success)
1206 {
1207   struct ContinutionContext *cc = cls;
1208   struct NeighbourMapEntry *n = lookup_neighbour (&cc->address->peer);
1209
1210   if (GNUNET_YES != success)
1211   {
1212     GNUNET_assert (strlen (cc->address->transport_name) > 0);
1213     GNUNET_ATS_address_destroyed (GST_ats, cc->address, cc->session);
1214   }
1215   if ((NULL == neighbours) || (NULL == n) || (n->state == S_DISCONNECT))
1216   {
1217     GNUNET_HELLO_address_free (cc->address);
1218     GNUNET_free (cc);
1219     return;
1220   }
1221
1222   if ((GNUNET_YES == success) &&
1223       ((n->state == S_NOT_CONNECTED) || (n->state == S_CONNECT_SENT)))
1224   {
1225     change_state (n, S_CONNECT_SENT);
1226     GNUNET_HELLO_address_free (cc->address);
1227     GNUNET_free (cc);
1228     return;
1229   }
1230
1231   if ((GNUNET_NO == success) &&
1232       ((n->state == S_NOT_CONNECTED) || (n->state == S_CONNECT_SENT)))
1233   {
1234 #if DEBUG_TRANSPORT
1235     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1236                 "Failed to send CONNECT_MSG to peer `%4s' with address '%s' session %p, asking ATS for new address \n",
1237                 GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session);
1238 #endif
1239     change_state (n, S_NOT_CONNECTED);
1240     if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
1241       GNUNET_SCHEDULER_cancel (n->ats_suggest);
1242     n->ats_suggest =
1243         GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, &ats_suggest_cancel,
1244                                       n);
1245     GNUNET_ATS_suggest_address (GST_ats, &n->id);
1246   }
1247   GNUNET_HELLO_address_free (cc->address);
1248   GNUNET_free (cc);
1249 }
1250
1251
1252 static void
1253 ats_request (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1254 {
1255   struct NeighbourMapEntry *n = cls;
1256   n->ats_request = GNUNET_SCHEDULER_NO_TASK;
1257
1258   n->ats_suggest =
1259     GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel,
1260                                   n);
1261 }
1262
1263
1264 /**
1265  * We tried to switch addresses with an peer already connected. If it failed,
1266  * we should tell ATS to not use this address anymore (until it is re-validated).
1267  *
1268  * @param cls the 'struct NeighbourMapEntry'
1269  * @param target peer to send the message to
1270  * @param success GNUNET_OK on success
1271  */
1272 static void
1273 send_switch_address_continuation (void *cls,
1274                                   const struct GNUNET_PeerIdentity *target,
1275                                   int success)
1276 {
1277   struct ContinutionContext *cc = cls;
1278   struct NeighbourMapEntry *n;
1279
1280   if (neighbours == NULL)
1281   {
1282     GNUNET_HELLO_address_free (cc->address);
1283     GNUNET_free (cc);
1284     return;                     /* neighbour is going away */
1285   }
1286
1287   n = lookup_neighbour (&cc->address->peer);
1288   if ((n == NULL) || (is_disconnecting (n)))
1289   {
1290     GNUNET_HELLO_address_free (cc->address);
1291     GNUNET_free (cc);
1292     return;                     /* neighbour is going away */
1293   }
1294
1295   GNUNET_assert ((n->state == S_CONNECTED) || (n->state == S_FAST_RECONNECT));
1296   if (GNUNET_YES != success)
1297   {
1298
1299     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1300                 "Failed to switch connected peer `%s' in state %s to address '%s' session %X, asking ATS for new address \n",
1301                 GNUNET_i2s (&n->id), print_state(n->state), GST_plugins_a2s (cc->address), cc->session);
1302
1303     GNUNET_assert (strlen (cc->address->transport_name) > 0);
1304     GNUNET_ATS_address_destroyed (GST_ats, cc->address, cc->session);
1305
1306     if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
1307     {
1308       GNUNET_SCHEDULER_cancel (n->ats_suggest);
1309       n->ats_suggest = GNUNET_SCHEDULER_NO_TASK;
1310     }
1311
1312     if (n->state == S_FAST_RECONNECT)
1313     {
1314       if (GNUNET_SCHEDULER_NO_TASK == n->ats_request)
1315       {
1316         /* Throtteled ATS request for fast reconnect */
1317         struct GNUNET_TIME_Relative delay = GNUNET_TIME_relative_multiply(FAST_RECONNECT_RATE, n->fast_reconnect_attempts);
1318         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1319                     "Fast reconnect attempt %u failed, delay ATS request for %llu ms\n", n->fast_reconnect_attempts, delay.rel_value);
1320         n->ats_request =
1321             GNUNET_SCHEDULER_add_delayed (delay,
1322                                           ats_request,
1323                                           n);
1324       }
1325     }
1326     else
1327     {
1328       /* Immediate ATS request for connected peers */
1329       n->ats_suggest =
1330         GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel,
1331                                       n);
1332       GNUNET_ATS_suggest_address (GST_ats, &n->id);
1333     }
1334     GNUNET_HELLO_address_free (cc->address);
1335     GNUNET_free (cc);
1336     return;
1337   }
1338   /* Tell ATS that switching addresses was successful */
1339   switch (n->state)
1340   {
1341   case S_CONNECTED:
1342     if (n->address_state == FRESH)
1343     {
1344       GST_validation_set_address_use (cc->address, cc->session, GNUNET_YES,  __LINE__);
1345       GNUNET_ATS_address_update (GST_ats, cc->address, cc->session, NULL, 0);
1346       GNUNET_break (cc->session == n->session);
1347       GNUNET_ATS_address_in_use (GST_ats, cc->address, cc->session, GNUNET_YES);
1348       n->address_state = USED;
1349     }
1350     break;
1351   case S_FAST_RECONNECT:
1352 #if DEBUG_TRANSPORT
1353     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1354                 "Successful fast reconnect to peer `%s'\n",
1355                 GNUNET_i2s (&n->id));
1356 #endif
1357     change_state (n, S_CONNECTED);
1358     neighbours_connected++;
1359     GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), 1,
1360                               GNUNET_NO);
1361
1362     if (n->address_state == FRESH)
1363     {
1364       GST_validation_set_address_use (cc->address, cc->session, GNUNET_YES,  __LINE__);
1365       GNUNET_ATS_address_update (GST_ats, cc->address, cc->session, NULL, 0);
1366       GNUNET_ATS_address_in_use (GST_ats, cc->address, cc->session, GNUNET_YES);
1367       n->address_state = USED;
1368     }
1369
1370     if (n->keepalive_task == GNUNET_SCHEDULER_NO_TASK)
1371       n->keepalive_task =
1372           GNUNET_SCHEDULER_add_now (&neighbour_keepalive_task, n);
1373
1374     /* Updating quotas */
1375     GST_neighbours_set_incoming_quota (&n->id, n->bandwidth_in);
1376     send_outbound_quota (target, n->bandwidth_out);
1377
1378   default:
1379     break;
1380   }
1381   GNUNET_HELLO_address_free (cc->address);
1382   GNUNET_free (cc);
1383 }
1384
1385
1386 /**
1387  * We tried to send a SESSION_CONNECT message to another peer.  If this
1388  * succeeded, we change the state.  If it failed, we should tell
1389  * ATS to not use this address anymore (until it is re-validated).
1390  *
1391  * @param cls the 'struct NeighbourMapEntry'
1392  * @param target peer to send the message to
1393  * @param success GNUNET_OK on success
1394  */
1395 static void
1396 send_connect_ack_continuation (void *cls,
1397                                const struct GNUNET_PeerIdentity *target,
1398                                int success)
1399 {
1400   struct ContinutionContext *cc = cls;
1401   struct NeighbourMapEntry *n;
1402
1403   if (neighbours == NULL)
1404   {
1405     GNUNET_HELLO_address_free (cc->address);
1406     GNUNET_free (cc);
1407     return;                     /* neighbour is going away */
1408   }
1409
1410   n = lookup_neighbour (&cc->address->peer);
1411   if ((n == NULL) || (is_disconnecting (n)))
1412   {
1413     GNUNET_HELLO_address_free (cc->address);
1414     GNUNET_free (cc);
1415     return;                     /* neighbour is going away */
1416   }
1417
1418   if (GNUNET_YES == success)
1419   {
1420     GNUNET_HELLO_address_free (cc->address);
1421     GNUNET_free (cc);
1422     return;                     /* sending successful */
1423   }
1424
1425   /* sending failed, ask for next address  */
1426 #if DEBUG_TRANSPORT
1427   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1428               "Failed to send CONNECT_MSG to peer `%4s' with address '%s' session %X, asking ATS for new address \n",
1429               GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session);
1430 #endif
1431   if (n->state != S_NOT_CONNECTED)
1432     change_state (n, S_NOT_CONNECTED);
1433   GNUNET_assert (strlen (cc->address->transport_name) > 0);
1434   GNUNET_ATS_address_destroyed (GST_ats, cc->address, cc->session);
1435
1436   if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
1437     GNUNET_SCHEDULER_cancel (n->ats_suggest);
1438   n->ats_suggest =
1439       GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel,
1440                                     n);
1441   GNUNET_ATS_suggest_address (GST_ats, &n->id);
1442   GNUNET_HELLO_address_free (cc->address);
1443   GNUNET_free (cc);
1444 }
1445
1446
1447 /**
1448  * For an existing neighbour record, set the active connection to
1449  * use the given address.
1450  *
1451  * @param peer identity of the peer to switch the address for
1452  * @param address address of the other peer, NULL if other peer
1453  *                       connected to us
1454  * @param session session to use (or NULL)
1455  * @param ats performance data
1456  * @param ats_count number of entries in ats
1457  * @param bandwidth_in inbound quota to be used when connection is up
1458  * @param bandwidth_out outbound quota to be used when connection is up
1459  * @return GNUNET_YES if we are currently connected, GNUNET_NO if the
1460  *         connection is not up (yet)
1461  */
1462 int
1463 GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer,
1464                                        const struct GNUNET_HELLO_Address
1465                                        *address,
1466                                        struct Session *session,
1467                                        const struct GNUNET_ATS_Information *ats,
1468                                        uint32_t ats_count,
1469                                        struct GNUNET_BANDWIDTH_Value32NBO
1470                                        bandwidth_in,
1471                                        struct GNUNET_BANDWIDTH_Value32NBO
1472                                        bandwidth_out)
1473 {
1474   struct NeighbourMapEntry *n;
1475   struct SessionConnectMessage connect_msg;
1476   struct ContinutionContext *cc;
1477   size_t msg_len;
1478   size_t ret;
1479
1480   if (neighbours == NULL)
1481   {
1482     /* This can happen during shutdown */
1483     return GNUNET_NO;
1484   }
1485   n = lookup_neighbour (peer);
1486   if (NULL == n)
1487     return GNUNET_NO;
1488   if (n->state == S_DISCONNECT)
1489   {
1490     /* We are disconnecting, nothing to do here */
1491     return GNUNET_NO;
1492   }
1493   GNUNET_assert (address->transport_name != NULL);
1494   if ((session == NULL) && (0 == address->address_length))
1495   {
1496     GNUNET_break_op (0);
1497     /* FIXME: is this actually possible? When does this happen? */
1498     if (strlen (address->transport_name) > 0)
1499       GNUNET_ATS_address_destroyed (GST_ats, address, session);
1500     GNUNET_ATS_suggest_address (GST_ats, peer);
1501     return GNUNET_NO;
1502   }
1503
1504   /* checks successful and neighbour != NULL */
1505   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1506               "ATS tells us to switch to address '%s' session %p for peer `%s' in state `%s'\n",
1507               (address->address_length != 0) ? GST_plugins_a2s (address): "<inbound>",
1508               session,
1509               GNUNET_i2s (peer),
1510               print_state (n->state));
1511
1512   if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
1513   {
1514     GNUNET_SCHEDULER_cancel (n->ats_suggest);
1515     n->ats_suggest = GNUNET_SCHEDULER_NO_TASK;
1516   }
1517
1518
1519   if (n->state == S_FAST_RECONNECT)
1520   {
1521     /* Throtteled fast reconnect */
1522
1523     if (NULL == n->fast_reconnect_address)
1524     {
1525       n->fast_reconnect_address = GNUNET_HELLO_address_copy (address);
1526
1527     }
1528     else if (0 == GNUNET_HELLO_address_cmp(address, n->fast_reconnect_address))
1529     {
1530       n->fast_reconnect_attempts ++;
1531
1532       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1533                 "FAST RECONNECT to peer `%s' and address '%s' with identical address attempt %u\n",
1534                 GNUNET_i2s (&n->id), GST_plugins_a2s (address), n->fast_reconnect_attempts);
1535     }
1536   }
1537   else
1538   {
1539     n->fast_reconnect_attempts = 0;
1540   }
1541
1542   /* do not switch addresses just update quotas */
1543   if ((n->state == S_CONNECTED) && (NULL != n->address) &&
1544       (0 == GNUNET_HELLO_address_cmp (address, n->address)) &&
1545       (n->session == session))
1546   {
1547     n->bandwidth_in = bandwidth_in;
1548     n->bandwidth_out = bandwidth_out;
1549     GST_neighbours_set_incoming_quota (&n->id, n->bandwidth_in);
1550     send_outbound_quota (peer, n->bandwidth_out);
1551     return GNUNET_NO;
1552   }
1553   if (n->state == S_CONNECTED)
1554   {
1555     /* mark old address as no longer used */
1556     GNUNET_assert (NULL != n->address);
1557     if (n->address_state == USED)
1558     {
1559       GST_validation_set_address_use (n->address, n->session, GNUNET_NO,  __LINE__);
1560       GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_NO);
1561       n->address_state = UNUSED;
1562     }
1563   }
1564
1565   /* set new address */
1566   if (NULL != n->address)
1567     GNUNET_HELLO_address_free (n->address);
1568   n->address = GNUNET_HELLO_address_copy (address);
1569   n->address_state = FRESH;
1570   n->bandwidth_in = bandwidth_in;
1571   n->bandwidth_out = bandwidth_out;
1572   GNUNET_SCHEDULER_cancel (n->timeout_task);
1573   n->timeout_task =
1574       GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1575                                     &neighbour_timeout_task, n);
1576
1577   if (NULL != address_change_cb && n->state == S_CONNECTED)
1578     address_change_cb (callback_cls, &n->id, n->address); 
1579
1580   /* Obtain an session for this address from plugin */
1581   struct GNUNET_TRANSPORT_PluginFunctions *papi;
1582   papi = GST_plugins_find (address->transport_name);
1583
1584   if (papi == NULL)
1585   {
1586     /* we don't have the plugin for this address */
1587     GNUNET_ATS_address_destroyed (GST_ats, n->address, NULL);
1588
1589     if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
1590       GNUNET_SCHEDULER_cancel (n->ats_suggest);
1591     n->ats_suggest =  GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT,
1592                                       ats_suggest_cancel,
1593                                       n);
1594     GNUNET_ATS_suggest_address (GST_ats, &n->id);
1595     GNUNET_HELLO_address_free (n->address);
1596     n->address = NULL;
1597     n->session = NULL;
1598     return GNUNET_NO;
1599   }
1600
1601   if (session == NULL)
1602   {
1603     n->session = papi->get_session (papi->cls, address);
1604     /* Session could not be initiated */
1605     if (n->session == NULL)
1606     {
1607       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1608                   "Failed to obtain new session %p for peer `%s' and  address '%s'\n",
1609                   n->session, GNUNET_i2s (&n->id), GST_plugins_a2s (n->address));
1610
1611       GNUNET_ATS_address_destroyed (GST_ats, n->address, NULL);
1612
1613       if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
1614         GNUNET_SCHEDULER_cancel (n->ats_suggest);
1615       n->ats_suggest =  GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT,
1616                                         ats_suggest_cancel,
1617                                         n);
1618       GNUNET_ATS_suggest_address (GST_ats, &n->id);
1619       GNUNET_HELLO_address_free (n->address);
1620       n->address = NULL;
1621       n->session = NULL;
1622       return GNUNET_NO;
1623     }
1624
1625     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1626                 "Obtained new session %p for peer `%s' and  address '%s'\n",
1627                  n->session, GNUNET_i2s (&n->id), GST_plugins_a2s (n->address));
1628     /* Telling ATS about new session */
1629     GNUNET_ATS_address_update (GST_ats, n->address, n->session, NULL, 0);
1630   }
1631   else
1632   {
1633     n->session = session;
1634     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1635                 "Using existing session %p for peer `%s' and  address '%s'\n",
1636                 n->session,
1637                 GNUNET_i2s (&n->id),
1638                 (address->address_length != 0) ? GST_plugins_a2s (address): "<inbound>");
1639   }
1640
1641   switch (n->state)
1642   {
1643   case S_NOT_CONNECTED:
1644   case S_CONNECT_SENT:
1645     msg_len = sizeof (struct SessionConnectMessage);
1646     connect_msg.header.size = htons (msg_len);
1647     connect_msg.header.type =
1648         htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT);
1649     connect_msg.reserved = htonl (0);
1650     connect_msg.timestamp =
1651         GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
1652
1653     cc = GNUNET_malloc (sizeof (struct ContinutionContext));
1654     cc->session = n->session;
1655     cc->address = GNUNET_HELLO_address_copy (address);
1656
1657     ret = send_with_session (n,
1658       (const char *) &connect_msg, msg_len,
1659       UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL,
1660       &send_connect_continuation, cc);
1661
1662     return GNUNET_NO;
1663   case S_CONNECT_RECV:
1664     /* We received a CONNECT message and asked ATS for an address */
1665     msg_len = sizeof (struct SessionConnectMessage);
1666     connect_msg.header.size = htons (msg_len);
1667     connect_msg.header.type =
1668         htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT_ACK);
1669     connect_msg.reserved = htonl (0);
1670     connect_msg.timestamp =
1671         GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
1672     cc = GNUNET_malloc (sizeof (struct ContinutionContext));
1673     cc->session = n->session;
1674     cc->address = GNUNET_HELLO_address_copy (address);
1675
1676     ret = send_with_session(n,
1677                             (const void *) &connect_msg, msg_len,
1678                             UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL,
1679                             &send_connect_ack_continuation,
1680                             cc);
1681     return GNUNET_NO;
1682   case S_CONNECTED:
1683   case S_FAST_RECONNECT:
1684     /* connected peer is switching addresses or tries fast reconnect */
1685     msg_len = sizeof (struct SessionConnectMessage);
1686     connect_msg.header.size = htons (msg_len);
1687     connect_msg.header.type =
1688         htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT);
1689     connect_msg.reserved = htonl (0);
1690     connect_msg.timestamp =
1691         GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
1692     cc = GNUNET_malloc (sizeof (struct ContinutionContext));
1693     cc->session = n->session;
1694     cc->address = GNUNET_HELLO_address_copy (address);
1695     ret = send_with_session(n,
1696                             (const void *) &connect_msg, msg_len,
1697                             UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL,
1698                             &send_switch_address_continuation, cc);
1699     if (ret == GNUNET_SYSERR)
1700     {
1701       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1702                   "Failed to send CONNECT_MESSAGE to `%4s' using address '%s' session %X\n",
1703                   GNUNET_i2s (peer), GST_plugins_a2s (address), session);
1704     }
1705     return GNUNET_NO;
1706   default:
1707     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1708                 "Invalid connection state to switch addresses %u \n", n->state);
1709     GNUNET_break_op (0);
1710     return GNUNET_NO;
1711   }
1712 }
1713
1714
1715 /**
1716  * Obtain current latency information for the given neighbour.
1717  *
1718  * @param peer
1719  * @return observed latency of the address, FOREVER if the address was
1720  *         never successfully validated
1721  */
1722 struct GNUNET_TIME_Relative
1723 GST_neighbour_get_latency (const struct GNUNET_PeerIdentity *peer)
1724 {
1725   struct NeighbourMapEntry *n;
1726
1727   n = lookup_neighbour (peer);
1728   if ((NULL == n) || ((n->address == NULL) && (n->session == NULL)))
1729     return GNUNET_TIME_UNIT_FOREVER_REL;
1730
1731   return n->latency;
1732 }
1733
1734 /**
1735  * Obtain current address information for the given neighbour.
1736  *
1737  * @param peer
1738  * @return address currently used
1739  */
1740 struct GNUNET_HELLO_Address *
1741 GST_neighbour_get_current_address (const struct GNUNET_PeerIdentity *peer)
1742 {
1743   struct NeighbourMapEntry *n;
1744
1745   n = lookup_neighbour (peer);
1746   if ((NULL == n) || ((n->address == NULL) && (n->session == NULL)))
1747     return NULL;
1748
1749   return n->address;
1750 }
1751
1752
1753
1754 /**
1755  * Create an entry in the neighbour map for the given peer
1756  *
1757  * @param peer peer to create an entry for
1758  * @return new neighbour map entry
1759  */
1760 static struct NeighbourMapEntry *
1761 setup_neighbour (const struct GNUNET_PeerIdentity *peer)
1762 {
1763   struct NeighbourMapEntry *n;
1764
1765 #if DEBUG_TRANSPORT
1766   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1767               "Unknown peer `%s', creating new neighbour\n", GNUNET_i2s (peer));
1768 #endif
1769   n = GNUNET_malloc (sizeof (struct NeighbourMapEntry));
1770   n->id = *peer;
1771   n->state = S_NOT_CONNECTED;
1772   n->latency = GNUNET_TIME_relative_get_forever ();
1773   GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
1774                                  GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
1775                                  MAX_BANDWIDTH_CARRY_S);
1776   n->timeout_task =
1777       GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1778                                     &neighbour_timeout_task, n);
1779   GNUNET_assert (GNUNET_OK ==
1780                  GNUNET_CONTAINER_multihashmap_put (neighbours,
1781                                                     &n->id.hashPubKey, n,
1782                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1783   return n;
1784 }
1785
1786
1787 /**
1788  * Try to create a connection to the given target (eventually).
1789  *
1790  * @param target peer to try to connect to
1791  */
1792 void
1793 GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target)
1794 {
1795   struct NeighbourMapEntry *n;
1796
1797   // This can happen during shutdown
1798   if (neighbours == NULL)
1799   {
1800     return;
1801   }
1802 #if DEBUG_TRANSPORT
1803   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to connect to peer `%s'\n",
1804               GNUNET_i2s (target));
1805 #endif
1806   if (0 ==
1807       memcmp (target, &GST_my_identity, sizeof (struct GNUNET_PeerIdentity)))
1808   {
1809     /* my own hello */
1810     return;
1811   }
1812   n = lookup_neighbour (target);
1813
1814   if (NULL != n)
1815   {
1816     if ((S_CONNECTED == n->state) || (is_connecting (n)))
1817       return;                   /* already connecting or connected */
1818     if (is_disconnecting (n))
1819       change_state (n, S_NOT_CONNECTED);
1820   }
1821
1822
1823   if (n == NULL)
1824     n = setup_neighbour (target);
1825 #if DEBUG_TRANSPORT
1826   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1827               "Asking ATS for suggested address to connect to peer `%s'\n",
1828               GNUNET_i2s (&n->id));
1829 #endif
1830
1831   GNUNET_ATS_suggest_address (GST_ats, &n->id);
1832 }
1833
1834 /**
1835  * Test if we're connected to the given peer.
1836  *
1837  * @param target peer to test
1838  * @return GNUNET_YES if we are connected, GNUNET_NO if not
1839  */
1840 int
1841 GST_neighbours_test_connected (const struct GNUNET_PeerIdentity *target)
1842 {
1843   struct NeighbourMapEntry *n;
1844
1845   // This can happen during shutdown
1846   if (neighbours == NULL)
1847   {
1848     return GNUNET_NO;
1849   }
1850
1851   n = lookup_neighbour (target);
1852
1853   if ((NULL == n) || (S_CONNECTED != n->state))
1854     return GNUNET_NO;           /* not connected */
1855   return GNUNET_YES;
1856 }
1857
1858 /**
1859  * A session was terminated. Take note.
1860  *
1861  * @param peer identity of the peer where the session died
1862  * @param session session that is gone
1863  */
1864 void
1865 GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer,
1866                                    struct Session *session)
1867 {
1868   struct NeighbourMapEntry *n;
1869
1870   if (neighbours == NULL)
1871   {
1872     /* This can happen during shutdown */
1873     return;
1874   }
1875
1876 #if DEBUG_TRANSPORT
1877   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Session %X to peer `%s' ended \n",
1878               session, GNUNET_i2s (peer));
1879 #endif
1880
1881   n = lookup_neighbour (peer);
1882   if (NULL == n)
1883     return;
1884   if (session != n->session)
1885     return;                     /* doesn't affect us */
1886   if (n->state == S_CONNECTED)
1887   {
1888     if (n->address_state == USED)
1889     {
1890       GST_validation_set_address_use (n->address, n->session, GNUNET_NO,  __LINE__);
1891       GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_NO);
1892       n->address_state = UNUSED;
1893
1894     }
1895   }
1896
1897   if (NULL != n->address)
1898   {
1899     GNUNET_HELLO_address_free (n->address);
1900     n->address = NULL;
1901   }
1902   n->session = NULL;
1903
1904   /* not connected anymore anyway, shouldn't matter */
1905   if (S_CONNECTED != n->state)
1906     return;
1907
1908   if (n->keepalive_task != GNUNET_SCHEDULER_NO_TASK)
1909   {
1910     GNUNET_SCHEDULER_cancel (n->keepalive_task);
1911     n->keepalive_task = GNUNET_SCHEDULER_NO_TASK;
1912     n->expect_latency_response = GNUNET_NO;
1913   }
1914
1915   /* connected, try fast reconnect */
1916   /* statistics "transport" : "# peers connected" -= 1
1917    * neighbours_connected -= 1
1918    * BUT: no disconnect_cb to notify clients about disconnect
1919    */
1920
1921   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying fast reconnect to peer `%s'\n",
1922               GNUNET_i2s (peer));
1923
1924   GNUNET_assert (neighbours_connected > 0);
1925   change_state (n, S_FAST_RECONNECT);
1926   neighbours_connected--;
1927   GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), -1,
1928                             GNUNET_NO);
1929
1930
1931   /* We are connected, so ask ATS to switch addresses */
1932   GNUNET_SCHEDULER_cancel (n->timeout_task);
1933   n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_DISCONNECT_SESSION_TIMEOUT,
1934                                     &neighbour_timeout_task, n);
1935   /* try QUICKLY to re-establish a connection, reduce timeout! */
1936   if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
1937     GNUNET_SCHEDULER_cancel (n->ats_suggest);
1938   n->ats_suggest = GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT,
1939                                     &ats_suggest_cancel,
1940                                     n);
1941   GNUNET_ATS_suggest_address (GST_ats, peer);
1942 }
1943
1944
1945 /**
1946  * Transmit a message to the given target using the active connection.
1947  *
1948  * @param target destination
1949  * @param msg message to send
1950  * @param msg_size number of bytes in msg
1951  * @param timeout when to fail with timeout
1952  * @param cont function to call when done
1953  * @param cont_cls closure for 'cont'
1954  */
1955 void
1956 GST_neighbours_send (const struct GNUNET_PeerIdentity *target, const void *msg,
1957                      size_t msg_size, struct GNUNET_TIME_Relative timeout,
1958                      GST_NeighbourSendContinuation cont, void *cont_cls)
1959 {
1960   struct NeighbourMapEntry *n;
1961   struct MessageQueue *mq;
1962
1963   // This can happen during shutdown
1964   if (neighbours == NULL)
1965   {
1966     return;
1967   }
1968
1969   n = lookup_neighbour (target);
1970   if ((n == NULL) || (!is_connected (n)))
1971   {
1972     GNUNET_STATISTICS_update (GST_stats,
1973                               gettext_noop
1974                               ("# messages not sent (no such peer or not connected)"),
1975                               1, GNUNET_NO);
1976 #if DEBUG_TRANSPORT
1977     if (n == NULL)
1978       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1979                   "Could not send message to peer `%s': unknown neighbour",
1980                   GNUNET_i2s (target));
1981     else if (!is_connected (n))
1982       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1983                   "Could not send message to peer `%s': not connected\n",
1984                   GNUNET_i2s (target));
1985 #endif
1986     if (NULL != cont)
1987       cont (cont_cls, GNUNET_SYSERR);
1988     return;
1989   }
1990
1991   if ((n->session == NULL) && (n->address == NULL))
1992   {
1993     GNUNET_STATISTICS_update (GST_stats,
1994                               gettext_noop
1995                               ("# messages not sent (no such peer or not connected)"),
1996                               1, GNUNET_NO);
1997 #if DEBUG_TRANSPORT
1998     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1999                 "Could not send message to peer `%s': no address available\n",
2000                 GNUNET_i2s (target));
2001 #endif
2002
2003     if (NULL != cont)
2004       cont (cont_cls, GNUNET_SYSERR);
2005     return;
2006   }
2007
2008   GNUNET_assert (msg_size >= sizeof (struct GNUNET_MessageHeader));
2009   GNUNET_STATISTICS_update (GST_stats,
2010                             gettext_noop
2011                             ("# bytes in message queue for other peers"),
2012                             msg_size, GNUNET_NO);
2013   mq = GNUNET_malloc (sizeof (struct MessageQueue) + msg_size);
2014   mq->cont = cont;
2015   mq->cont_cls = cont_cls;
2016   /* FIXME: this memcpy can be up to 7% of our total runtime! */
2017   memcpy (&mq[1], msg, msg_size);
2018   mq->message_buf = (const char *) &mq[1];
2019   mq->message_buf_size = msg_size;
2020   mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
2021   GNUNET_CONTAINER_DLL_insert_tail (n->messages_head, n->messages_tail, mq);
2022
2023   if ((GNUNET_SCHEDULER_NO_TASK == n->transmission_task) &&
2024       (NULL == n->is_active))
2025     n->transmission_task = GNUNET_SCHEDULER_add_now (&transmission_task, n);
2026 }
2027
2028
2029 /**
2030  * We have received a message from the given sender.  How long should
2031  * we delay before receiving more?  (Also used to keep the peer marked
2032  * as live).
2033  *
2034  * @param sender sender of the message
2035  * @param size size of the message
2036  * @param do_forward set to GNUNET_YES if the message should be forwarded to clients
2037  *                   GNUNET_NO if the neighbour is not connected or violates the quota,
2038  *                   GNUNET_SYSERR if the connection is not fully up yet
2039  * @return how long to wait before reading more from this sender
2040  */
2041 struct GNUNET_TIME_Relative
2042 GST_neighbours_calculate_receive_delay (const struct GNUNET_PeerIdentity
2043                                         *sender, ssize_t size, int *do_forward)
2044 {
2045   struct NeighbourMapEntry *n;
2046   struct GNUNET_TIME_Relative ret;
2047
2048   // This can happen during shutdown
2049   if (neighbours == NULL)
2050   {
2051     return GNUNET_TIME_UNIT_FOREVER_REL;
2052   }
2053
2054   n = lookup_neighbour (sender);
2055   if (n == NULL)
2056   {
2057     GST_neighbours_try_connect (sender);
2058     n = lookup_neighbour (sender);
2059     if (NULL == n)
2060     {
2061       GNUNET_STATISTICS_update (GST_stats,
2062                                 gettext_noop
2063                                 ("# messages discarded due to lack of neighbour record"),
2064                                 1, GNUNET_NO);
2065       *do_forward = GNUNET_NO;
2066       return GNUNET_TIME_UNIT_ZERO;
2067     }
2068   }
2069   if (!is_connected (n))
2070   {
2071     *do_forward = GNUNET_SYSERR;
2072     return GNUNET_TIME_UNIT_ZERO;
2073   }
2074   if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, size))
2075   {
2076     n->quota_violation_count++;
2077 #if DEBUG_TRANSPORT
2078     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2079                 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
2080                 n->in_tracker.available_bytes_per_s__,
2081                 n->quota_violation_count);
2082 #endif
2083     /* Discount 32k per violation */
2084     GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, -32 * 1024);
2085   }
2086   else
2087   {
2088     if (n->quota_violation_count > 0)
2089     {
2090       /* try to add 32k back */
2091       GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, 32 * 1024);
2092       n->quota_violation_count--;
2093     }
2094   }
2095   if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
2096   {
2097     GNUNET_STATISTICS_update (GST_stats,
2098                               gettext_noop
2099                               ("# bandwidth quota violations by other peers"),
2100                               1, GNUNET_NO);
2101     *do_forward = GNUNET_NO;
2102     return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
2103   }
2104   *do_forward = GNUNET_YES;
2105   ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 32 * 1024);
2106   if (ret.rel_value > 0)
2107   {
2108 #if DEBUG_TRANSPORT
2109     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2110                 "Throttling read (%llu bytes excess at %u b/s), waiting %llu ms before reading more.\n",
2111                 (unsigned long long) n->in_tracker.
2112                 consumption_since_last_update__,
2113                 (unsigned int) n->in_tracker.available_bytes_per_s__,
2114                 (unsigned long long) ret.rel_value);
2115 #endif
2116     GNUNET_STATISTICS_update (GST_stats,
2117                               gettext_noop ("# ms throttling suggested"),
2118                               (int64_t) ret.rel_value, GNUNET_NO);
2119   }
2120   return ret;
2121 }
2122
2123
2124 /**
2125  * Keep the connection to the given neighbour alive longer,
2126  * we received a KEEPALIVE (or equivalent).
2127  *
2128  * @param neighbour neighbour to keep alive
2129  */
2130 void
2131 GST_neighbours_keepalive (const struct GNUNET_PeerIdentity *neighbour)
2132 {
2133   struct NeighbourMapEntry *n;
2134
2135   // This can happen during shutdown
2136   if (neighbours == NULL)
2137   {
2138     return;
2139   }
2140
2141   n = lookup_neighbour (neighbour);
2142   if (NULL == n)
2143   {
2144     GNUNET_STATISTICS_update (GST_stats,
2145                               gettext_noop
2146                               ("# KEEPALIVE messages discarded (not connected)"),
2147                               1, GNUNET_NO);
2148     return;
2149   }
2150   GNUNET_SCHEDULER_cancel (n->timeout_task);
2151   n->timeout_task =
2152       GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2153                                     &neighbour_timeout_task, n);
2154
2155   /* send reply to measure latency */
2156   if (S_CONNECTED != n->state)
2157     return;
2158
2159   struct GNUNET_MessageHeader m;
2160
2161   m.size = htons (sizeof (struct GNUNET_MessageHeader));
2162   m.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE_RESPONSE);
2163
2164   send_with_session(n,
2165       (const void *) &m, sizeof (m),
2166       UINT32_MAX,
2167       GNUNET_TIME_UNIT_FOREVER_REL,
2168       NULL, NULL);
2169 }
2170
2171 /**
2172  * We received a KEEP_ALIVE_RESPONSE message and use this to calculate latency
2173  * to this peer
2174  *
2175  * @param neighbour neighbour to keep alive
2176  * @param ats performance data
2177  * @param ats_count number of entries in ats
2178  */
2179 void
2180 GST_neighbours_keepalive_response (const struct GNUNET_PeerIdentity *neighbour,
2181                                    const struct GNUNET_ATS_Information *ats,
2182                                    uint32_t ats_count)
2183 {
2184   struct NeighbourMapEntry *n;
2185   struct GNUNET_ATS_Information *ats_new;
2186   uint32_t latency;
2187
2188   if (neighbours == NULL)
2189   {
2190     // This can happen during shutdown
2191     return;
2192   }
2193
2194   n = lookup_neighbour (neighbour);
2195   if ((NULL == n) || (n->state != S_CONNECTED))
2196   {
2197     GNUNET_STATISTICS_update (GST_stats,
2198                               gettext_noop
2199                               ("# KEEPALIVE_RESPONSE messages discarded (not connected)"),
2200                               1, GNUNET_NO);
2201     return;
2202   }
2203   if (n->expect_latency_response != GNUNET_YES)
2204   {
2205     GNUNET_STATISTICS_update (GST_stats,
2206                               gettext_noop
2207                               ("# KEEPALIVE_RESPONSE messages discarded (not expected)"),
2208                               1, GNUNET_NO);
2209     return;
2210   }
2211   n->expect_latency_response = GNUNET_NO;
2212
2213   GNUNET_assert (n->keep_alive_sent.abs_value !=
2214                  GNUNET_TIME_absolute_get_zero ().abs_value);
2215   n->latency =
2216       GNUNET_TIME_absolute_get_difference (n->keep_alive_sent,
2217                                            GNUNET_TIME_absolute_get ());
2218 #if DEBUG_TRANSPORT
2219   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Latency for peer `%s' is %llu ms\n",
2220               GNUNET_i2s (&n->id), n->latency.rel_value);
2221 #endif
2222
2223
2224   if (n->latency.rel_value == GNUNET_TIME_relative_get_forever ().rel_value)
2225   {
2226     GNUNET_ATS_address_update (GST_ats, n->address, n->session, ats, ats_count);
2227   }
2228   else
2229   {
2230     ats_new =
2231         GNUNET_malloc (sizeof (struct GNUNET_ATS_Information) *
2232                        (ats_count + 1));
2233     memcpy (ats_new, ats, sizeof (struct GNUNET_ATS_Information) * ats_count);
2234
2235     /* add latency */
2236     ats_new[ats_count].type = htonl (GNUNET_ATS_QUALITY_NET_DELAY);
2237     if (n->latency.rel_value > UINT32_MAX)
2238       latency = UINT32_MAX;
2239     else
2240       latency = n->latency.rel_value;
2241     ats_new[ats_count].value = htonl (latency);
2242
2243     GNUNET_ATS_address_update (GST_ats, n->address, n->session, ats_new,
2244                                ats_count + 1);
2245     GNUNET_free (ats_new);
2246   }
2247 }
2248
2249
2250 /**
2251  * Change the incoming quota for the given peer.
2252  *
2253  * @param neighbour identity of peer to change qutoa for
2254  * @param quota new quota
2255  */
2256 void
2257 GST_neighbours_set_incoming_quota (const struct GNUNET_PeerIdentity *neighbour,
2258                                    struct GNUNET_BANDWIDTH_Value32NBO quota)
2259 {
2260   struct NeighbourMapEntry *n;
2261
2262   // This can happen during shutdown
2263   if (neighbours == NULL)
2264   {
2265     return;
2266   }
2267
2268   n = lookup_neighbour (neighbour);
2269   if (n == NULL)
2270   {
2271     GNUNET_STATISTICS_update (GST_stats,
2272                               gettext_noop
2273                               ("# SET QUOTA messages ignored (no such peer)"),
2274                               1, GNUNET_NO);
2275     return;
2276   }
2277 #if DEBUG_TRANSPORT
2278   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2279               "Setting inbound quota of %u Bps for peer `%s' to all clients\n",
2280               ntohl (quota.value__), GNUNET_i2s (&n->id));
2281 #endif
2282   GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker, quota);
2283   if (0 != ntohl (quota.value__))
2284     return;
2285 #if DEBUG_TRANSPORT
2286   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s' due to `%s'\n",
2287               GNUNET_i2s (&n->id), "SET_QUOTA");
2288 #endif
2289   if (is_connected (n))
2290     GNUNET_STATISTICS_update (GST_stats,
2291                               gettext_noop ("# disconnects due to quota of 0"),
2292                               1, GNUNET_NO);
2293   disconnect_neighbour (n);
2294 }
2295
2296
2297 /**
2298  * Closure for the neighbours_iterate function.
2299  */
2300 struct IteratorContext
2301 {
2302   /**
2303    * Function to call on each connected neighbour.
2304    */
2305   GST_NeighbourIterator cb;
2306
2307   /**
2308    * Closure for 'cb'.
2309    */
2310   void *cb_cls;
2311 };
2312
2313
2314 /**
2315  * Call the callback from the closure for each connected neighbour.
2316  *
2317  * @param cls the 'struct IteratorContext'
2318  * @param key the hash of the public key of the neighbour
2319  * @param value the 'struct NeighbourMapEntry'
2320  * @return GNUNET_OK (continue to iterate)
2321  */
2322 static int
2323 neighbours_iterate (void *cls, const GNUNET_HashCode * key, void *value)
2324 {
2325   struct IteratorContext *ic = cls;
2326   struct NeighbourMapEntry *n = value;
2327
2328   if (!is_connected (n))
2329     return GNUNET_OK;
2330
2331   ic->cb (ic->cb_cls, &n->id, NULL, 0, n->address);
2332   return GNUNET_OK;
2333 }
2334
2335
2336 /**
2337  * Iterate over all connected neighbours.
2338  *
2339  * @param cb function to call
2340  * @param cb_cls closure for cb
2341  */
2342 void
2343 GST_neighbours_iterate (GST_NeighbourIterator cb, void *cb_cls)
2344 {
2345   struct IteratorContext ic;
2346
2347   // This can happen during shutdown
2348   if (neighbours == NULL)
2349   {
2350     return;
2351   }
2352
2353   ic.cb = cb;
2354   ic.cb_cls = cb_cls;
2355   GNUNET_CONTAINER_multihashmap_iterate (neighbours, &neighbours_iterate, &ic);
2356 }
2357
2358 /**
2359  * If we have an active connection to the given target, it must be shutdown.
2360  *
2361  * @param target peer to disconnect from
2362  */
2363 void
2364 GST_neighbours_force_disconnect (const struct GNUNET_PeerIdentity *target)
2365 {
2366   struct NeighbourMapEntry *n;
2367
2368   // This can happen during shutdown
2369   if (neighbours == NULL)
2370   {
2371     return;
2372   }
2373
2374   n = lookup_neighbour (target);
2375   if (NULL == n)
2376     return;                     /* not active */
2377   disconnect_neighbour (n);
2378 }
2379
2380
2381 /**
2382  * We received a disconnect message from the given peer,
2383  * validate and process.
2384  *
2385  * @param peer sender of the message
2386  * @param msg the disconnect message
2387  */
2388 void
2389 GST_neighbours_handle_disconnect_message (const struct GNUNET_PeerIdentity
2390                                           *peer,
2391                                           const struct GNUNET_MessageHeader
2392                                           *msg)
2393 {
2394   struct NeighbourMapEntry *n;
2395   const struct SessionDisconnectMessage *sdm;
2396   GNUNET_HashCode hc;
2397
2398 #if DEBUG_TRANSPORT
2399   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2400               "Received DISCONNECT message from peer `%s'\n",
2401               GNUNET_i2s (peer));
2402 #endif
2403
2404   if (ntohs (msg->size) != sizeof (struct SessionDisconnectMessage))
2405   {
2406     // GNUNET_break_op (0);
2407     GNUNET_STATISTICS_update (GST_stats,
2408                               gettext_noop
2409                               ("# disconnect messages ignored (old format)"), 1,
2410                               GNUNET_NO);
2411     return;
2412   }
2413   sdm = (const struct SessionDisconnectMessage *) msg;
2414   n = lookup_neighbour (peer);
2415   if (NULL == n)
2416     return;                     /* gone already */
2417   if (GNUNET_TIME_absolute_ntoh (sdm->timestamp).abs_value <=
2418       n->connect_ts.abs_value)
2419   {
2420     GNUNET_STATISTICS_update (GST_stats,
2421                               gettext_noop
2422                               ("# disconnect messages ignored (timestamp)"), 1,
2423                               GNUNET_NO);
2424     return;
2425   }
2426   GNUNET_CRYPTO_hash (&sdm->public_key,
2427                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2428                       &hc);
2429   if (0 != memcmp (peer, &hc, sizeof (struct GNUNET_PeerIdentity)))
2430   {
2431     GNUNET_break_op (0);
2432     return;
2433   }
2434   if (ntohl (sdm->purpose.size) !=
2435       sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
2436       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) +
2437       sizeof (struct GNUNET_TIME_AbsoluteNBO))
2438   {
2439     GNUNET_break_op (0);
2440     return;
2441   }
2442   if (GNUNET_OK !=
2443       GNUNET_CRYPTO_rsa_verify
2444       (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT, &sdm->purpose,
2445        &sdm->signature, &sdm->public_key))
2446   {
2447     GNUNET_break_op (0);
2448     return;
2449   }
2450   GST_neighbours_force_disconnect (peer);
2451 }
2452
2453
2454 /**
2455  * We received a 'SESSION_CONNECT_ACK' message from the other peer.
2456  * Consider switching to it.
2457  *
2458  * @param message possibly a 'struct SessionConnectMessage' (check format)
2459  * @param peer identity of the peer to switch the address for
2460  * @param address address of the other peer, NULL if other peer
2461  *                       connected to us
2462  * @param session session to use (or NULL)
2463  * @param ats performance data
2464  * @param ats_count number of entries in ats
2465  */
2466 void
2467 GST_neighbours_handle_connect_ack (const struct GNUNET_MessageHeader *message,
2468                                    const struct GNUNET_PeerIdentity *peer,
2469                                    const struct GNUNET_HELLO_Address *address,
2470                                    struct Session *session,
2471                                    const struct GNUNET_ATS_Information *ats,
2472                                    uint32_t ats_count)
2473 {
2474   const struct SessionConnectMessage *scm;
2475   struct GNUNET_MessageHeader msg;
2476   struct NeighbourMapEntry *n;
2477   size_t msg_len;
2478   size_t ret;
2479
2480   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2481               "Received CONNECT_ACK message from peer `%s'\n",
2482               GNUNET_i2s (peer));
2483
2484   if (ntohs (message->size) != sizeof (struct SessionConnectMessage))
2485   {
2486     GNUNET_break_op (0);
2487     return;
2488   }
2489   scm = (const struct SessionConnectMessage *) message;
2490   GNUNET_break_op (ntohl (scm->reserved) == 0);
2491   n = lookup_neighbour (peer);
2492   if (NULL == n)
2493   {
2494     /* we did not send 'CONNECT' -- at least not recently */
2495     GNUNET_STATISTICS_update (GST_stats,
2496                               gettext_noop
2497                               ("# unexpected CONNECT_ACK messages (no peer)"),
2498                               1, GNUNET_NO);
2499     return;
2500   }
2501
2502   /* Additional check
2503    *
2504    * ((n->state != S_CONNECT_RECV) && (n->address != NULL)):
2505    *
2506    * We also received an CONNECT message, switched from SENDT to RECV and
2507    * ATS already suggested us an address after a successful blacklist check
2508    */
2509
2510   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2511               "Received CONNECT_ACK message from peer `%s' in state `%s'\n",
2512               GNUNET_i2s (peer),
2513               print_state(n->state));
2514
2515   if ((n->address != NULL) && (n->state == S_CONNECTED))
2516   {
2517     /* After fast reconnect: send ACK (ACK) even when we are connected */
2518     msg_len = sizeof (msg);
2519     msg.size = htons (msg_len);
2520     msg.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK);
2521
2522     ret = send_with_session(n,
2523               (const char *) &msg, msg_len,
2524               UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL,
2525               NULL, NULL);
2526
2527     if (ret == GNUNET_SYSERR)
2528       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2529                   "Failed to send SESSION_ACK to `%4s' using address '%s' session %X\n",
2530                   GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session);
2531     return;
2532   }
2533
2534   if ((n->state != S_CONNECT_SENT) &&
2535       ((n->state != S_CONNECT_RECV) && (n->address != NULL)))
2536   {
2537     GNUNET_STATISTICS_update (GST_stats,
2538                               gettext_noop
2539                               ("# unexpected CONNECT_ACK messages"), 1,
2540                               GNUNET_NO);
2541     return;
2542   }
2543   if (n->state != S_CONNECTED)
2544     change_state (n, S_CONNECTED);
2545
2546   if (NULL != session)
2547   {
2548     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2549                      "transport-ats",
2550                      "Giving ATS session %p of plugin %s for peer %s\n",
2551                      session, address->transport_name, GNUNET_i2s (peer));
2552   }
2553   GNUNET_ATS_address_update (GST_ats, address, session, ats, ats_count);
2554   GNUNET_assert (NULL != n->address);
2555
2556   if ((n->address_state == FRESH) && (0 == GNUNET_HELLO_address_cmp(address, n->address)))
2557   {
2558     GST_validation_set_address_use (n->address, n->session, GNUNET_YES,  __LINE__);
2559     GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_YES);
2560     n->address_state = USED;
2561   }
2562
2563   GST_neighbours_set_incoming_quota (&n->id, n->bandwidth_in);
2564
2565   /* send ACK (ACK) */
2566   msg_len = sizeof (msg);
2567   msg.size = htons (msg_len);
2568   msg.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK);
2569
2570   ret = send_with_session(n,
2571             (const char *) &msg, msg_len,
2572             UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL,
2573             NULL, NULL);
2574
2575   if (ret == GNUNET_SYSERR)
2576     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2577                 "Failed to send SESSION_ACK to `%4s' using address '%s' session %X\n",
2578                 GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session);
2579
2580
2581   if (n->keepalive_task == GNUNET_SCHEDULER_NO_TASK)
2582     n->keepalive_task = GNUNET_SCHEDULER_add_now (&neighbour_keepalive_task, n);
2583
2584   neighbours_connected++;
2585   GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), 1,
2586                             GNUNET_NO);
2587 #if DEBUG_TRANSPORT
2588   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2589               "Notify about connect of `%4s' using address '%s' session %X LINE %u\n",
2590               GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session,
2591               __LINE__);
2592 #endif
2593   connect_notify_cb (callback_cls, &n->id, ats, ats_count);
2594   send_outbound_quota (peer, n->bandwidth_out);
2595
2596 }
2597
2598
2599 void
2600 GST_neighbours_handle_ack (const struct GNUNET_MessageHeader *message,
2601                            const struct GNUNET_PeerIdentity *peer,
2602                            const struct GNUNET_HELLO_Address *address,
2603                            struct Session *session,
2604                            const struct GNUNET_ATS_Information *ats,
2605                            uint32_t ats_count)
2606 {
2607   struct NeighbourMapEntry *n;
2608
2609 #if DEBUG_TRANSPORT
2610   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ACK message from peer `%s'\n",
2611               GNUNET_i2s (peer));
2612 #endif
2613
2614   if (ntohs (message->size) != sizeof (struct GNUNET_MessageHeader))
2615   {
2616     GNUNET_break_op (0);
2617     return;
2618   }
2619   n = lookup_neighbour (peer);
2620   if (NULL == n)
2621   {
2622     GNUNET_break (0);
2623     return;
2624   }
2625   if (S_CONNECTED == n->state)
2626     return;
2627   if (!is_connecting (n))
2628   {
2629     GNUNET_STATISTICS_update (GST_stats,
2630                               gettext_noop ("# unexpected ACK messages"), 1,
2631                               GNUNET_NO);
2632     return;
2633   }
2634   change_state (n, S_CONNECTED);
2635   if (NULL != session)
2636     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2637                      "transport-ats",
2638                      "Giving ATS session %p of plugin %s for peer %s\n",
2639                      session, address->transport_name, GNUNET_i2s (peer));
2640   GNUNET_ATS_address_update (GST_ats, address, session, ats, ats_count);
2641   GNUNET_assert (n->address != NULL);
2642
2643   if ((n->address_state == FRESH) && (0 == GNUNET_HELLO_address_cmp(address, n->address)))
2644   {
2645     GST_validation_set_address_use (n->address, n->session, GNUNET_YES,  __LINE__);
2646     GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_YES);
2647     n->address_state = USED;
2648   }
2649
2650
2651   neighbours_connected++;
2652   GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), 1,
2653                             GNUNET_NO);
2654
2655   GST_neighbours_set_incoming_quota (&n->id, n->bandwidth_in);
2656   if (n->keepalive_task == GNUNET_SCHEDULER_NO_TASK)
2657     n->keepalive_task = GNUNET_SCHEDULER_add_now (&neighbour_keepalive_task, n);
2658 #if DEBUG_TRANSPORT
2659   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2660               "Notify about connect of `%4s' using address '%s' session %X LINE %u\n",
2661               GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session,
2662               __LINE__);
2663 #endif
2664   connect_notify_cb (callback_cls, &n->id, ats, ats_count);
2665   send_outbound_quota (peer, n->bandwidth_out);
2666 }
2667
2668 struct BlackListCheckContext
2669 {
2670   struct GNUNET_ATS_Information *ats;
2671
2672   uint32_t ats_count;
2673
2674   struct Session *session;
2675
2676   struct GNUNET_HELLO_Address *address;
2677
2678   struct GNUNET_TIME_Absolute ts;
2679 };
2680
2681
2682 static void
2683 handle_connect_blacklist_cont (void *cls,
2684                                const struct GNUNET_PeerIdentity *peer,
2685                                int result)
2686 {
2687   struct NeighbourMapEntry *n;
2688   struct BlackListCheckContext *bcc = cls;
2689
2690 #if DEBUG_TRANSPORT
2691   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2692               "Blacklist check due to CONNECT message: `%s'\n",
2693               GNUNET_i2s (peer),
2694               (result == GNUNET_OK) ? "ALLOWED" : "FORBIDDEN");
2695 #endif
2696
2697   /* not allowed */
2698   if (GNUNET_OK != result)
2699   {
2700     GNUNET_HELLO_address_free (bcc->address);
2701     GNUNET_free (bcc);
2702     return;
2703   }
2704
2705   n = lookup_neighbour (peer);
2706   if (NULL == n)
2707     n = setup_neighbour (peer);
2708
2709   if (bcc->ts.abs_value > n->connect_ts.abs_value)
2710   {
2711     if (NULL != bcc->session)
2712       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2713                        "transport-ats",
2714                        "Giving ATS session %p of address `%s' for peer %s\n",
2715                        bcc->session, GST_plugins_a2s (bcc->address),
2716                        GNUNET_i2s (peer));
2717     /* Tell ATS about the session, so ATS can suggest it if it likes it. */
2718
2719     GNUNET_ATS_address_update (GST_ats, bcc->address, bcc->session, bcc->ats,
2720                                bcc->ats_count);
2721     n->connect_ts = bcc->ts;
2722   }
2723
2724   GNUNET_HELLO_address_free (bcc->address);
2725   GNUNET_free (bcc);
2726
2727   if (n->state != S_CONNECT_RECV)
2728     change_state (n, S_CONNECT_RECV);
2729
2730
2731   /* Ask ATS for an address to connect via that address */
2732   if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
2733     GNUNET_SCHEDULER_cancel (n->ats_suggest);
2734   n->ats_suggest =
2735       GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel,
2736                                     n);
2737   GNUNET_ATS_suggest_address (GST_ats, peer);
2738 }
2739
2740 /**
2741  * We received a 'SESSION_CONNECT' message from the other peer.
2742  * Consider switching to it.
2743  *
2744  * @param message possibly a 'struct SessionConnectMessage' (check format)
2745  * @param peer identity of the peer to switch the address for
2746  * @param address address of the other peer, NULL if other peer
2747  *                       connected to us
2748  * @param session session to use (or NULL)
2749  * @param ats performance data
2750  * @param ats_count number of entries in ats (excluding 0-termination)
2751  */
2752 void
2753 GST_neighbours_handle_connect (const struct GNUNET_MessageHeader *message,
2754                                const struct GNUNET_PeerIdentity *peer,
2755                                const struct GNUNET_HELLO_Address *address,
2756                                struct Session *session,
2757                                const struct GNUNET_ATS_Information *ats,
2758                                uint32_t ats_count)
2759 {
2760   const struct SessionConnectMessage *scm;
2761   struct BlackListCheckContext *bcc = NULL;
2762   struct NeighbourMapEntry *n;
2763
2764 #if DEBUG_TRANSPORT
2765   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2766               "Received CONNECT message from peer `%s'\n", GNUNET_i2s (peer));
2767 #endif
2768
2769   if (ntohs (message->size) != sizeof (struct SessionConnectMessage))
2770   {
2771     GNUNET_break_op (0);
2772     return;
2773   }
2774
2775   scm = (const struct SessionConnectMessage *) message;
2776   GNUNET_break_op (ntohl (scm->reserved) == 0);
2777
2778   GNUNET_ATS_address_update (GST_ats, address, session, ats, ats_count);
2779
2780   n = lookup_neighbour (peer);
2781   if ((n != NULL) && ((S_CONNECTED == n->state) || (S_FAST_RECONNECT == n->state)))
2782   {
2783     /* connected peer switches addresses or is trying to do a fast reconnect*/
2784     return;
2785   }
2786
2787
2788   /* we are not connected to this peer */
2789   /* do blacklist check */
2790   bcc =
2791       GNUNET_malloc (sizeof (struct BlackListCheckContext) +
2792                      sizeof (struct GNUNET_ATS_Information) * (ats_count + 1));
2793   bcc->ts = GNUNET_TIME_absolute_ntoh (scm->timestamp);
2794   bcc->ats_count = ats_count + 1;
2795   bcc->address = GNUNET_HELLO_address_copy (address);
2796   bcc->session = session;
2797   bcc->ats = (struct GNUNET_ATS_Information *) &bcc[1];
2798   memcpy (bcc->ats, ats, sizeof (struct GNUNET_ATS_Information) * ats_count);
2799   bcc->ats[ats_count].type = htonl (GNUNET_ATS_QUALITY_NET_DELAY);
2800   bcc->ats[ats_count].value =
2801       htonl ((uint32_t) GST_neighbour_get_latency (peer).rel_value);
2802   GST_blacklist_test_allowed (peer, address->transport_name,
2803                               &handle_connect_blacklist_cont, bcc);
2804 }
2805
2806
2807 /* end of file gnunet-service-transport_neighbours.c */