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