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