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