7dfe5b25a7a7a3d383d9e29f515c87bc6926c5b1
[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 (cc->address), cc->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       if (cc->session != n->session)
1256         GNUNET_break (0);
1257       GNUNET_ATS_address_in_use (GST_ats, cc->address, cc->session, GNUNET_YES);
1258       n->address_state = USED;
1259     }
1260     break;
1261   case S_FAST_RECONNECT:
1262 #if DEBUG_TRANSPORT
1263     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1264                 "Successful fast reconnect to peer `%s'\n",
1265                 GNUNET_i2s (&n->id));
1266 #endif
1267     change_state (n, S_CONNECTED);
1268     neighbours_connected++;
1269     GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), 1,
1270                               GNUNET_NO);
1271
1272     if (n->address_state == FRESH)
1273     {
1274       GST_validation_set_address_use (cc->address, cc->session, GNUNET_YES);
1275       GNUNET_ATS_address_update (GST_ats, cc->address, cc->session, NULL, 0);
1276       GNUNET_ATS_address_in_use (GST_ats, cc->address, cc->session, GNUNET_YES);
1277       n->address_state = USED;
1278     }
1279
1280     if (n->keepalive_task == GNUNET_SCHEDULER_NO_TASK)
1281       n->keepalive_task =
1282           GNUNET_SCHEDULER_add_now (&neighbour_keepalive_task, n);
1283
1284     /* Updating quotas */
1285     GST_neighbours_set_incoming_quota (&n->id, n->bandwidth_in);
1286     send_outbound_quota (target, n->bandwidth_out);
1287
1288   default:
1289     break;
1290   }
1291   GNUNET_HELLO_address_free (cc->address);
1292   GNUNET_free (cc);
1293 }
1294
1295
1296 /**
1297  * We tried to send a SESSION_CONNECT message to another peer.  If this
1298  * succeeded, we change the state.  If it failed, we should tell
1299  * ATS to not use this address anymore (until it is re-validated).
1300  *
1301  * @param cls the 'struct NeighbourMapEntry'
1302  * @param target peer to send the message to
1303  * @param success GNUNET_OK on success
1304  */
1305 static void
1306 send_connect_ack_continuation (void *cls,
1307                                const struct GNUNET_PeerIdentity *target,
1308                                int success)
1309 {
1310   struct ContinutionContext *cc = cls;
1311   struct NeighbourMapEntry *n;
1312
1313   if (neighbours == NULL)
1314   {
1315     GNUNET_HELLO_address_free (cc->address);
1316     GNUNET_free (cc);
1317     return;                     /* neighbour is going away */
1318   }
1319
1320   n = lookup_neighbour (&cc->address->peer);
1321   if ((n == NULL) || (is_disconnecting (n)))
1322   {
1323     GNUNET_HELLO_address_free (cc->address);
1324     GNUNET_free (cc);
1325     return;                     /* neighbour is going away */
1326   }
1327
1328   if (GNUNET_YES == success)
1329   {
1330     GNUNET_HELLO_address_free (cc->address);
1331     GNUNET_free (cc);
1332     return;                     /* sending successful */
1333   }
1334
1335   /* sending failed, ask for next address  */
1336 #if DEBUG_TRANSPORT
1337   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1338               "Failed to send CONNECT_MSG to peer `%4s' with address '%s' session %X, asking ATS for new address \n",
1339               GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session);
1340 #endif
1341   change_state (n, S_NOT_CONNECTED);
1342   GNUNET_assert (strlen (cc->address->transport_name) > 0);
1343   GNUNET_ATS_address_destroyed (GST_ats, cc->address, cc->session);
1344
1345   if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
1346     GNUNET_SCHEDULER_cancel (n->ats_suggest);
1347   n->ats_suggest =
1348       GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel,
1349                                     n);
1350   GNUNET_ATS_suggest_address (GST_ats, &n->id);
1351   GNUNET_HELLO_address_free (cc->address);
1352   GNUNET_free (cc);
1353 }
1354
1355
1356 /**
1357  * For an existing neighbour record, set the active connection to
1358  * use the given address.
1359  *
1360  * @param peer identity of the peer to switch the address for
1361  * @param address address of the other peer, NULL if other peer
1362  *                       connected to us
1363  * @param session session to use (or NULL)
1364  * @param ats performance data
1365  * @param ats_count number of entries in ats
1366  * @param bandwidth_in inbound quota to be used when connection is up
1367  * @param bandwidth_out outbound quota to be used when connection is up
1368  * @return GNUNET_YES if we are currently connected, GNUNET_NO if the
1369  *         connection is not up (yet)
1370  */
1371 int
1372 GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer,
1373                                        const struct GNUNET_HELLO_Address
1374                                        *address,
1375                                        struct Session *session,
1376                                        const struct GNUNET_ATS_Information *ats,
1377                                        uint32_t ats_count,
1378                                        struct GNUNET_BANDWIDTH_Value32NBO
1379                                        bandwidth_in,
1380                                        struct GNUNET_BANDWIDTH_Value32NBO
1381                                        bandwidth_out)
1382 {
1383   struct NeighbourMapEntry *n;
1384   struct SessionConnectMessage connect_msg;
1385   struct ContinutionContext *cc;
1386   size_t msg_len;
1387   size_t ret;
1388
1389   if (neighbours == NULL)
1390   {
1391     /* This can happen during shutdown */
1392     return GNUNET_NO;
1393   }
1394   n = lookup_neighbour (peer);
1395   if (NULL == n)
1396     return GNUNET_NO;
1397   if (n->state == S_DISCONNECT)
1398   {
1399     /* We are disconnecting, nothing to do here */
1400     return GNUNET_NO;
1401   }
1402   GNUNET_assert (address->transport_name != NULL);
1403   if ((session == NULL) && (0 == address->address_length))
1404   {
1405     GNUNET_break_op (0);
1406     /* FIXME: is this actually possible? When does this happen? */
1407     if (strlen (address->transport_name) > 0)
1408       GNUNET_ATS_address_destroyed (GST_ats, address, session);
1409     GNUNET_ATS_suggest_address (GST_ats, peer);
1410     return GNUNET_NO;
1411   }
1412
1413   /* checks successful and neighbour != NULL */
1414   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1415               "ATS tells us to switch to address '%s' session %p for peer `%s' in state `%s'\n",
1416               (address->address_length != 0) ? GST_plugins_a2s (address): "<inbound>",
1417               session,
1418               GNUNET_i2s (peer),
1419               print_state (n->state));
1420
1421   if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
1422   {
1423     GNUNET_SCHEDULER_cancel (n->ats_suggest);
1424     n->ats_suggest = GNUNET_SCHEDULER_NO_TASK;
1425   }
1426   /* do not switch addresses just update quotas */
1427   if ((n->state == S_CONNECTED) && (NULL != n->address) &&
1428       (0 == GNUNET_HELLO_address_cmp (address, n->address)) &&
1429       (n->session == session))
1430   {
1431     n->bandwidth_in = bandwidth_in;
1432     n->bandwidth_out = bandwidth_out;
1433     GST_neighbours_set_incoming_quota (&n->id, n->bandwidth_in);
1434     send_outbound_quota (peer, n->bandwidth_out);
1435     return GNUNET_NO;
1436   }
1437   if (n->state == S_CONNECTED)
1438   {
1439     /* mark old address as no longer used */
1440     GNUNET_assert (NULL != n->address);
1441     if (n->address_state == USED)
1442     {
1443       GST_validation_set_address_use (n->address, n->session, GNUNET_NO);
1444       GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_NO);
1445       n->address_state = UNUSED;
1446     }
1447   }
1448
1449   /* set new address */
1450   if (NULL != n->address)
1451     GNUNET_HELLO_address_free (n->address);
1452   n->address = GNUNET_HELLO_address_copy (address);
1453   n->address_state = FRESH;
1454   n->bandwidth_in = bandwidth_in;
1455   n->bandwidth_out = bandwidth_out;
1456   GNUNET_SCHEDULER_cancel (n->timeout_task);
1457   n->timeout_task =
1458       GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1459                                     &neighbour_timeout_task, n);
1460
1461   if (NULL != address_change_cb && n->state == S_CONNECTED)
1462     address_change_cb (callback_cls, &n->id, n->address); 
1463
1464   /* Obtain an session for this address from plugin */
1465   struct GNUNET_TRANSPORT_PluginFunctions *papi;
1466   papi = GST_plugins_find (address->transport_name);
1467   GNUNET_assert (papi != NULL);
1468   if (session == NULL)
1469   {
1470     n->session = papi->get_session (papi->cls, address);
1471     /* Session could not be initiated */
1472     if (n->session == NULL)
1473     {
1474       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1475                   "Failed to obtain new session %p for peer `%s' and  address '%s'\n",
1476                   n->session, GNUNET_i2s (&n->id), GST_plugins_a2s (n->address));
1477
1478       GNUNET_ATS_address_destroyed (GST_ats, n->address, NULL);
1479
1480       if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
1481         GNUNET_SCHEDULER_cancel (n->ats_suggest);
1482       n->ats_suggest =  GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT,
1483                                         ats_suggest_cancel,
1484                                         n);
1485       GNUNET_ATS_suggest_address (GST_ats, &n->id);
1486       GNUNET_HELLO_address_free (n->address);
1487       n->address = NULL;
1488       n->session = NULL;
1489       return GNUNET_NO;
1490     }
1491
1492     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1493                 "Obtained new session %p for peer `%s' and  address '%s'\n",
1494                  n->session, GNUNET_i2s (&n->id), GST_plugins_a2s (n->address));
1495     /* Telling ATS about new session */
1496     GNUNET_ATS_address_update (GST_ats, n->address, n->session, NULL, 0);
1497   }
1498   else
1499   {
1500     n->session = session;
1501     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1502                 "Using existing session %p for peer `%s' and  address '%s'\n",
1503                 n->session,
1504                 GNUNET_i2s (&n->id),
1505                 (address->address_length != 0) ? GST_plugins_a2s (address): "<inbound>");
1506   }
1507
1508   switch (n->state)
1509   {
1510   case S_NOT_CONNECTED:
1511   case S_CONNECT_SENT:
1512     msg_len = sizeof (struct SessionConnectMessage);
1513     connect_msg.header.size = htons (msg_len);
1514     connect_msg.header.type =
1515         htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT);
1516     connect_msg.reserved = htonl (0);
1517     connect_msg.timestamp =
1518         GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
1519
1520     cc = GNUNET_malloc (sizeof (struct ContinutionContext));
1521     cc->session = n->session;
1522     cc->address = GNUNET_HELLO_address_copy (address);
1523
1524     ret = send_with_session (n,
1525       (const char *) &connect_msg, msg_len,
1526       UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL,
1527       &send_connect_continuation, cc);
1528
1529     return GNUNET_NO;
1530   case S_CONNECT_RECV:
1531     /* We received a CONNECT message and asked ATS for an address */
1532     msg_len = sizeof (struct SessionConnectMessage);
1533     connect_msg.header.size = htons (msg_len);
1534     connect_msg.header.type =
1535         htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT_ACK);
1536     connect_msg.reserved = htonl (0);
1537     connect_msg.timestamp =
1538         GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
1539     cc = GNUNET_malloc (sizeof (struct ContinutionContext));
1540     cc->session = n->session;
1541     cc->address = GNUNET_HELLO_address_copy (address);
1542
1543     ret = send_with_session(n,
1544                             (const void *) &connect_msg, msg_len,
1545                             UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL,
1546                             &send_connect_ack_continuation,
1547                             cc);
1548     return GNUNET_NO;
1549   case S_CONNECTED:
1550   case S_FAST_RECONNECT:
1551     /* connected peer is switching addresses or tries fast reconnect */
1552     msg_len = sizeof (struct SessionConnectMessage);
1553     connect_msg.header.size = htons (msg_len);
1554     connect_msg.header.type =
1555         htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT);
1556     connect_msg.reserved = htonl (0);
1557     connect_msg.timestamp =
1558         GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
1559     cc = GNUNET_malloc (sizeof (struct ContinutionContext));
1560     cc->session = n->session;
1561     cc->address = GNUNET_HELLO_address_copy (address);
1562     ret = send_with_session(n,
1563                             (const void *) &connect_msg, msg_len,
1564                             UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL,
1565                             &send_switch_address_continuation, cc);
1566     if (ret == GNUNET_SYSERR)
1567     {
1568       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1569                   "Failed to send CONNECT_MESSAGE to `%4s' using address '%s' session %X\n",
1570                   GNUNET_i2s (peer), GST_plugins_a2s (address), session);
1571     }
1572     return GNUNET_NO;
1573   default:
1574     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1575                 "Invalid connection state to switch addresses %u \n", n->state);
1576     GNUNET_break_op (0);
1577     return GNUNET_NO;
1578   }
1579 }
1580
1581
1582 /**
1583  * Obtain current latency information for the given neighbour.
1584  *
1585  * @param peer
1586  * @return observed latency of the address, FOREVER if the address was
1587  *         never successfully validated
1588  */
1589 struct GNUNET_TIME_Relative
1590 GST_neighbour_get_latency (const struct GNUNET_PeerIdentity *peer)
1591 {
1592   struct NeighbourMapEntry *n;
1593
1594   n = lookup_neighbour (peer);
1595   if ((NULL == n) || ((n->address == NULL) && (n->session == NULL)))
1596     return GNUNET_TIME_UNIT_FOREVER_REL;
1597
1598   return n->latency;
1599 }
1600
1601 /**
1602  * Obtain current address information for the given neighbour.
1603  *
1604  * @param peer
1605  * @return address currently used
1606  */
1607 struct GNUNET_HELLO_Address *
1608 GST_neighbour_get_current_address (const struct GNUNET_PeerIdentity *peer)
1609 {
1610   struct NeighbourMapEntry *n;
1611
1612   n = lookup_neighbour (peer);
1613   if ((NULL == n) || ((n->address == NULL) && (n->session == NULL)))
1614     return NULL;
1615
1616   return n->address;
1617 }
1618
1619
1620
1621 /**
1622  * Create an entry in the neighbour map for the given peer
1623  *
1624  * @param peer peer to create an entry for
1625  * @return new neighbour map entry
1626  */
1627 static struct NeighbourMapEntry *
1628 setup_neighbour (const struct GNUNET_PeerIdentity *peer)
1629 {
1630   struct NeighbourMapEntry *n;
1631
1632 #if DEBUG_TRANSPORT
1633   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1634               "Unknown peer `%s', creating new neighbour\n", GNUNET_i2s (peer));
1635 #endif
1636   n = GNUNET_malloc (sizeof (struct NeighbourMapEntry));
1637   n->id = *peer;
1638   n->state = S_NOT_CONNECTED;
1639   n->latency = GNUNET_TIME_relative_get_forever ();
1640   GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
1641                                  GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
1642                                  MAX_BANDWIDTH_CARRY_S);
1643   n->timeout_task =
1644       GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1645                                     &neighbour_timeout_task, n);
1646   GNUNET_assert (GNUNET_OK ==
1647                  GNUNET_CONTAINER_multihashmap_put (neighbours,
1648                                                     &n->id.hashPubKey, n,
1649                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1650   return n;
1651 }
1652
1653
1654 /**
1655  * Try to create a connection to the given target (eventually).
1656  *
1657  * @param target peer to try to connect to
1658  */
1659 void
1660 GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target)
1661 {
1662   struct NeighbourMapEntry *n;
1663
1664   // This can happen during shutdown
1665   if (neighbours == NULL)
1666   {
1667     return;
1668   }
1669 #if DEBUG_TRANSPORT
1670   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to connect to peer `%s'\n",
1671               GNUNET_i2s (target));
1672 #endif
1673   if (0 ==
1674       memcmp (target, &GST_my_identity, sizeof (struct GNUNET_PeerIdentity)))
1675   {
1676     /* my own hello */
1677     return;
1678   }
1679   n = lookup_neighbour (target);
1680
1681   if (NULL != n)
1682   {
1683     if ((S_CONNECTED == n->state) || (is_connecting (n)))
1684       return;                   /* already connecting or connected */
1685     if (is_disconnecting (n))
1686       change_state (n, S_NOT_CONNECTED);
1687   }
1688
1689
1690   if (n == NULL)
1691     n = setup_neighbour (target);
1692 #if DEBUG_TRANSPORT
1693   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1694               "Asking ATS for suggested address to connect to peer `%s'\n",
1695               GNUNET_i2s (&n->id));
1696 #endif
1697
1698   GNUNET_ATS_suggest_address (GST_ats, &n->id);
1699 }
1700
1701 /**
1702  * Test if we're connected to the given peer.
1703  *
1704  * @param target peer to test
1705  * @return GNUNET_YES if we are connected, GNUNET_NO if not
1706  */
1707 int
1708 GST_neighbours_test_connected (const struct GNUNET_PeerIdentity *target)
1709 {
1710   struct NeighbourMapEntry *n;
1711
1712   // This can happen during shutdown
1713   if (neighbours == NULL)
1714   {
1715     return GNUNET_NO;
1716   }
1717
1718   n = lookup_neighbour (target);
1719
1720   if ((NULL == n) || (S_CONNECTED != n->state))
1721     return GNUNET_NO;           /* not connected */
1722   return GNUNET_YES;
1723 }
1724
1725 /**
1726  * A session was terminated. Take note.
1727  *
1728  * @param peer identity of the peer where the session died
1729  * @param session session that is gone
1730  */
1731 void
1732 GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer,
1733                                    struct Session *session)
1734 {
1735   struct NeighbourMapEntry *n;
1736
1737   if (neighbours == NULL)
1738   {
1739     /* This can happen during shutdown */
1740     return;
1741   }
1742
1743 #if DEBUG_TRANSPORT
1744   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Session %X to peer `%s' ended \n",
1745               session, GNUNET_i2s (peer));
1746 #endif
1747
1748   n = lookup_neighbour (peer);
1749   if (NULL == n)
1750     return;
1751   if (session != n->session)
1752     return;                     /* doesn't affect us */
1753   if (n->state == S_CONNECTED)
1754   {
1755     if (n->address_state == USED)
1756     {
1757       GST_validation_set_address_use (n->address, n->session, GNUNET_NO);
1758       GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_NO);
1759       n->address_state = UNUSED;
1760     }
1761   }
1762
1763   if (NULL != n->address)
1764   {
1765     GNUNET_HELLO_address_free (n->address);
1766     n->address = NULL;
1767   }
1768   n->session = NULL;
1769
1770   /* not connected anymore anyway, shouldn't matter */
1771   if (S_CONNECTED != n->state)
1772     return;
1773
1774   if (n->keepalive_task != GNUNET_SCHEDULER_NO_TASK)
1775   {
1776     GNUNET_SCHEDULER_cancel (n->keepalive_task);
1777     n->keepalive_task = GNUNET_SCHEDULER_NO_TASK;
1778     n->expect_latency_response = GNUNET_NO;
1779   }
1780
1781   /* connected, try fast reconnect */
1782   /* statistics "transport" : "# peers connected" -= 1
1783    * neighbours_connected -= 1
1784    * BUT: no disconnect_cb to notify clients about disconnect
1785    */
1786 #if DEBUG_TRANSPORT
1787   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying fast reconnect to peer `%s'\n",
1788               GNUNET_i2s (peer));
1789 #endif
1790   GNUNET_assert (neighbours_connected > 0);
1791   change_state (n, S_FAST_RECONNECT);
1792   neighbours_connected--;
1793   GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), -1,
1794                             GNUNET_NO);
1795
1796
1797   /* We are connected, so ask ATS to switch addresses */
1798   GNUNET_SCHEDULER_cancel (n->timeout_task);
1799   n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_DISCONNECT_SESSION_TIMEOUT,
1800                                     &neighbour_timeout_task, n);
1801   /* try QUICKLY to re-establish a connection, reduce timeout! */
1802   if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
1803     GNUNET_SCHEDULER_cancel (n->ats_suggest);
1804   n->ats_suggest = GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT,
1805                                     &ats_suggest_cancel,
1806                                     n);
1807   GNUNET_ATS_suggest_address (GST_ats, peer);
1808 }
1809
1810
1811 /**
1812  * Transmit a message to the given target using the active connection.
1813  *
1814  * @param target destination
1815  * @param msg message to send
1816  * @param msg_size number of bytes in msg
1817  * @param timeout when to fail with timeout
1818  * @param cont function to call when done
1819  * @param cont_cls closure for 'cont'
1820  */
1821 void
1822 GST_neighbours_send (const struct GNUNET_PeerIdentity *target, const void *msg,
1823                      size_t msg_size, struct GNUNET_TIME_Relative timeout,
1824                      GST_NeighbourSendContinuation cont, void *cont_cls)
1825 {
1826   struct NeighbourMapEntry *n;
1827   struct MessageQueue *mq;
1828
1829   // This can happen during shutdown
1830   if (neighbours == NULL)
1831   {
1832     return;
1833   }
1834
1835   n = lookup_neighbour (target);
1836   if ((n == NULL) || (!is_connected (n)))
1837   {
1838     GNUNET_STATISTICS_update (GST_stats,
1839                               gettext_noop
1840                               ("# messages not sent (no such peer or not connected)"),
1841                               1, GNUNET_NO);
1842 #if DEBUG_TRANSPORT
1843     if (n == NULL)
1844       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1845                   "Could not send message to peer `%s': unknown neighbour",
1846                   GNUNET_i2s (target));
1847     else if (!is_connected (n))
1848       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1849                   "Could not send message to peer `%s': not connected\n",
1850                   GNUNET_i2s (target));
1851 #endif
1852     if (NULL != cont)
1853       cont (cont_cls, GNUNET_SYSERR);
1854     return;
1855   }
1856
1857   if ((n->session == NULL) && (n->address == NULL))
1858   {
1859     GNUNET_STATISTICS_update (GST_stats,
1860                               gettext_noop
1861                               ("# messages not sent (no such peer or not connected)"),
1862                               1, GNUNET_NO);
1863 #if DEBUG_TRANSPORT
1864     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1865                 "Could not send message to peer `%s': no address available\n",
1866                 GNUNET_i2s (target));
1867 #endif
1868
1869     if (NULL != cont)
1870       cont (cont_cls, GNUNET_SYSERR);
1871     return;
1872   }
1873
1874   GNUNET_assert (msg_size >= sizeof (struct GNUNET_MessageHeader));
1875   GNUNET_STATISTICS_update (GST_stats,
1876                             gettext_noop
1877                             ("# bytes in message queue for other peers"),
1878                             msg_size, GNUNET_NO);
1879   mq = GNUNET_malloc (sizeof (struct MessageQueue) + msg_size);
1880   mq->cont = cont;
1881   mq->cont_cls = cont_cls;
1882   /* FIXME: this memcpy can be up to 7% of our total runtime! */
1883   memcpy (&mq[1], msg, msg_size);
1884   mq->message_buf = (const char *) &mq[1];
1885   mq->message_buf_size = msg_size;
1886   mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1887   GNUNET_CONTAINER_DLL_insert_tail (n->messages_head, n->messages_tail, mq);
1888
1889   if ((GNUNET_SCHEDULER_NO_TASK == n->transmission_task) &&
1890       (NULL == n->is_active))
1891     n->transmission_task = GNUNET_SCHEDULER_add_now (&transmission_task, n);
1892 }
1893
1894
1895 /**
1896  * We have received a message from the given sender.  How long should
1897  * we delay before receiving more?  (Also used to keep the peer marked
1898  * as live).
1899  *
1900  * @param sender sender of the message
1901  * @param size size of the message
1902  * @param do_forward set to GNUNET_YES if the message should be forwarded to clients
1903  *                   GNUNET_NO if the neighbour is not connected or violates the quota,
1904  *                   GNUNET_SYSERR if the connection is not fully up yet
1905  * @return how long to wait before reading more from this sender
1906  */
1907 struct GNUNET_TIME_Relative
1908 GST_neighbours_calculate_receive_delay (const struct GNUNET_PeerIdentity
1909                                         *sender, ssize_t size, int *do_forward)
1910 {
1911   struct NeighbourMapEntry *n;
1912   struct GNUNET_TIME_Relative ret;
1913
1914   // This can happen during shutdown
1915   if (neighbours == NULL)
1916   {
1917     return GNUNET_TIME_UNIT_FOREVER_REL;
1918   }
1919
1920   n = lookup_neighbour (sender);
1921   if (n == NULL)
1922   {
1923     GST_neighbours_try_connect (sender);
1924     n = lookup_neighbour (sender);
1925     if (NULL == n)
1926     {
1927       GNUNET_STATISTICS_update (GST_stats,
1928                                 gettext_noop
1929                                 ("# messages discarded due to lack of neighbour record"),
1930                                 1, GNUNET_NO);
1931       *do_forward = GNUNET_NO;
1932       return GNUNET_TIME_UNIT_ZERO;
1933     }
1934   }
1935   if (!is_connected (n))
1936   {
1937     *do_forward = GNUNET_SYSERR;
1938     return GNUNET_TIME_UNIT_ZERO;
1939   }
1940   if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, size))
1941   {
1942     n->quota_violation_count++;
1943 #if DEBUG_TRANSPORT
1944     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1945                 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
1946                 n->in_tracker.available_bytes_per_s__,
1947                 n->quota_violation_count);
1948 #endif
1949     /* Discount 32k per violation */
1950     GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, -32 * 1024);
1951   }
1952   else
1953   {
1954     if (n->quota_violation_count > 0)
1955     {
1956       /* try to add 32k back */
1957       GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, 32 * 1024);
1958       n->quota_violation_count--;
1959     }
1960   }
1961   if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
1962   {
1963     GNUNET_STATISTICS_update (GST_stats,
1964                               gettext_noop
1965                               ("# bandwidth quota violations by other peers"),
1966                               1, GNUNET_NO);
1967     *do_forward = GNUNET_NO;
1968     return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
1969   }
1970   *do_forward = GNUNET_YES;
1971   ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 32 * 1024);
1972   if (ret.rel_value > 0)
1973   {
1974 #if DEBUG_TRANSPORT
1975     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1976                 "Throttling read (%llu bytes excess at %u b/s), waiting %llu ms before reading more.\n",
1977                 (unsigned long long) n->in_tracker.
1978                 consumption_since_last_update__,
1979                 (unsigned int) n->in_tracker.available_bytes_per_s__,
1980                 (unsigned long long) ret.rel_value);
1981 #endif
1982     GNUNET_STATISTICS_update (GST_stats,
1983                               gettext_noop ("# ms throttling suggested"),
1984                               (int64_t) ret.rel_value, GNUNET_NO);
1985   }
1986   return ret;
1987 }
1988
1989
1990 /**
1991  * Keep the connection to the given neighbour alive longer,
1992  * we received a KEEPALIVE (or equivalent).
1993  *
1994  * @param neighbour neighbour to keep alive
1995  */
1996 void
1997 GST_neighbours_keepalive (const struct GNUNET_PeerIdentity *neighbour)
1998 {
1999   struct NeighbourMapEntry *n;
2000
2001   // This can happen during shutdown
2002   if (neighbours == NULL)
2003   {
2004     return;
2005   }
2006
2007   n = lookup_neighbour (neighbour);
2008   if (NULL == n)
2009   {
2010     GNUNET_STATISTICS_update (GST_stats,
2011                               gettext_noop
2012                               ("# KEEPALIVE messages discarded (not connected)"),
2013                               1, GNUNET_NO);
2014     return;
2015   }
2016   GNUNET_SCHEDULER_cancel (n->timeout_task);
2017   n->timeout_task =
2018       GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2019                                     &neighbour_timeout_task, n);
2020
2021   /* send reply to measure latency */
2022   if (S_CONNECTED != n->state)
2023     return;
2024
2025   struct GNUNET_MessageHeader m;
2026
2027   m.size = htons (sizeof (struct GNUNET_MessageHeader));
2028   m.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE_RESPONSE);
2029
2030   send_with_session(n,
2031       (const void *) &m, sizeof (m),
2032       UINT32_MAX,
2033       GNUNET_TIME_UNIT_FOREVER_REL,
2034       NULL, NULL);
2035 }
2036
2037 /**
2038  * We received a KEEP_ALIVE_RESPONSE message and use this to calculate latency
2039  * to this peer
2040  *
2041  * @param neighbour neighbour to keep alive
2042  * @param ats performance data
2043  * @param ats_count number of entries in ats
2044  */
2045 void
2046 GST_neighbours_keepalive_response (const struct GNUNET_PeerIdentity *neighbour,
2047                                    const struct GNUNET_ATS_Information *ats,
2048                                    uint32_t ats_count)
2049 {
2050   struct NeighbourMapEntry *n;
2051   struct GNUNET_ATS_Information *ats_new;
2052   uint32_t latency;
2053
2054   if (neighbours == NULL)
2055   {
2056     // This can happen during shutdown
2057     return;
2058   }
2059
2060   n = lookup_neighbour (neighbour);
2061   if ((NULL == n) || (n->state != S_CONNECTED))
2062   {
2063     GNUNET_STATISTICS_update (GST_stats,
2064                               gettext_noop
2065                               ("# KEEPALIVE_RESPONSE messages discarded (not connected)"),
2066                               1, GNUNET_NO);
2067     return;
2068   }
2069   if (n->expect_latency_response != GNUNET_YES)
2070   {
2071     GNUNET_STATISTICS_update (GST_stats,
2072                               gettext_noop
2073                               ("# KEEPALIVE_RESPONSE messages discarded (not expected)"),
2074                               1, GNUNET_NO);
2075     return;
2076   }
2077   n->expect_latency_response = GNUNET_NO;
2078
2079   GNUNET_assert (n->keep_alive_sent.abs_value !=
2080                  GNUNET_TIME_absolute_get_zero ().abs_value);
2081   n->latency =
2082       GNUNET_TIME_absolute_get_difference (n->keep_alive_sent,
2083                                            GNUNET_TIME_absolute_get ());
2084 #if DEBUG_TRANSPORT
2085   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Latency for peer `%s' is %llu ms\n",
2086               GNUNET_i2s (&n->id), n->latency.rel_value);
2087 #endif
2088
2089
2090   if (n->latency.rel_value == GNUNET_TIME_relative_get_forever ().rel_value)
2091   {
2092     GNUNET_ATS_address_update (GST_ats, n->address, n->session, ats, ats_count);
2093   }
2094   else
2095   {
2096     ats_new =
2097         GNUNET_malloc (sizeof (struct GNUNET_ATS_Information) *
2098                        (ats_count + 1));
2099     memcpy (ats_new, ats, sizeof (struct GNUNET_ATS_Information) * ats_count);
2100
2101     /* add latency */
2102     ats_new[ats_count].type = htonl (GNUNET_ATS_QUALITY_NET_DELAY);
2103     if (n->latency.rel_value > UINT32_MAX)
2104       latency = UINT32_MAX;
2105     else
2106       latency = n->latency.rel_value;
2107     ats_new[ats_count].value = htonl (latency);
2108
2109     GNUNET_ATS_address_update (GST_ats, n->address, n->session, ats_new,
2110                                ats_count + 1);
2111     GNUNET_free (ats_new);
2112   }
2113 }
2114
2115
2116 /**
2117  * Change the incoming quota for the given peer.
2118  *
2119  * @param neighbour identity of peer to change qutoa for
2120  * @param quota new quota
2121  */
2122 void
2123 GST_neighbours_set_incoming_quota (const struct GNUNET_PeerIdentity *neighbour,
2124                                    struct GNUNET_BANDWIDTH_Value32NBO quota)
2125 {
2126   struct NeighbourMapEntry *n;
2127
2128   // This can happen during shutdown
2129   if (neighbours == NULL)
2130   {
2131     return;
2132   }
2133
2134   n = lookup_neighbour (neighbour);
2135   if (n == NULL)
2136   {
2137     GNUNET_STATISTICS_update (GST_stats,
2138                               gettext_noop
2139                               ("# SET QUOTA messages ignored (no such peer)"),
2140                               1, GNUNET_NO);
2141     return;
2142   }
2143 #if DEBUG_TRANSPORT
2144   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2145               "Setting inbound quota of %u Bps for peer `%s' to all clients\n",
2146               ntohl (quota.value__), GNUNET_i2s (&n->id));
2147 #endif
2148   GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker, quota);
2149   if (0 != ntohl (quota.value__))
2150     return;
2151 #if DEBUG_TRANSPORT
2152   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s' due to `%s'\n",
2153               GNUNET_i2s (&n->id), "SET_QUOTA");
2154 #endif
2155   if (is_connected (n))
2156     GNUNET_STATISTICS_update (GST_stats,
2157                               gettext_noop ("# disconnects due to quota of 0"),
2158                               1, GNUNET_NO);
2159   disconnect_neighbour (n);
2160 }
2161
2162
2163 /**
2164  * Closure for the neighbours_iterate function.
2165  */
2166 struct IteratorContext
2167 {
2168   /**
2169    * Function to call on each connected neighbour.
2170    */
2171   GST_NeighbourIterator cb;
2172
2173   /**
2174    * Closure for 'cb'.
2175    */
2176   void *cb_cls;
2177 };
2178
2179
2180 /**
2181  * Call the callback from the closure for each connected neighbour.
2182  *
2183  * @param cls the 'struct IteratorContext'
2184  * @param key the hash of the public key of the neighbour
2185  * @param value the 'struct NeighbourMapEntry'
2186  * @return GNUNET_OK (continue to iterate)
2187  */
2188 static int
2189 neighbours_iterate (void *cls, const GNUNET_HashCode * key, void *value)
2190 {
2191   struct IteratorContext *ic = cls;
2192   struct NeighbourMapEntry *n = value;
2193
2194   if (!is_connected (n))
2195     return GNUNET_OK;
2196
2197   ic->cb (ic->cb_cls, &n->id, NULL, 0, n->address);
2198   return GNUNET_OK;
2199 }
2200
2201
2202 /**
2203  * Iterate over all connected neighbours.
2204  *
2205  * @param cb function to call
2206  * @param cb_cls closure for cb
2207  */
2208 void
2209 GST_neighbours_iterate (GST_NeighbourIterator cb, void *cb_cls)
2210 {
2211   struct IteratorContext ic;
2212
2213   // This can happen during shutdown
2214   if (neighbours == NULL)
2215   {
2216     return;
2217   }
2218
2219   ic.cb = cb;
2220   ic.cb_cls = cb_cls;
2221   GNUNET_CONTAINER_multihashmap_iterate (neighbours, &neighbours_iterate, &ic);
2222 }
2223
2224 /**
2225  * If we have an active connection to the given target, it must be shutdown.
2226  *
2227  * @param target peer to disconnect from
2228  */
2229 void
2230 GST_neighbours_force_disconnect (const struct GNUNET_PeerIdentity *target)
2231 {
2232   struct NeighbourMapEntry *n;
2233
2234   // This can happen during shutdown
2235   if (neighbours == NULL)
2236   {
2237     return;
2238   }
2239
2240   n = lookup_neighbour (target);
2241   if (NULL == n)
2242     return;                     /* not active */
2243   disconnect_neighbour (n);
2244 }
2245
2246
2247 /**
2248  * We received a disconnect message from the given peer,
2249  * validate and process.
2250  *
2251  * @param peer sender of the message
2252  * @param msg the disconnect message
2253  */
2254 void
2255 GST_neighbours_handle_disconnect_message (const struct GNUNET_PeerIdentity
2256                                           *peer,
2257                                           const struct GNUNET_MessageHeader
2258                                           *msg)
2259 {
2260   struct NeighbourMapEntry *n;
2261   const struct SessionDisconnectMessage *sdm;
2262   GNUNET_HashCode hc;
2263
2264 #if DEBUG_TRANSPORT
2265   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2266               "Received DISCONNECT message from peer `%s'\n",
2267               GNUNET_i2s (peer));
2268 #endif
2269
2270   if (ntohs (msg->size) != sizeof (struct SessionDisconnectMessage))
2271   {
2272     // GNUNET_break_op (0);
2273     GNUNET_STATISTICS_update (GST_stats,
2274                               gettext_noop
2275                               ("# disconnect messages ignored (old format)"), 1,
2276                               GNUNET_NO);
2277     return;
2278   }
2279   sdm = (const struct SessionDisconnectMessage *) msg;
2280   n = lookup_neighbour (peer);
2281   if (NULL == n)
2282     return;                     /* gone already */
2283   if (GNUNET_TIME_absolute_ntoh (sdm->timestamp).abs_value <=
2284       n->connect_ts.abs_value)
2285   {
2286     GNUNET_STATISTICS_update (GST_stats,
2287                               gettext_noop
2288                               ("# disconnect messages ignored (timestamp)"), 1,
2289                               GNUNET_NO);
2290     return;
2291   }
2292   GNUNET_CRYPTO_hash (&sdm->public_key,
2293                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2294                       &hc);
2295   if (0 != memcmp (peer, &hc, sizeof (struct GNUNET_PeerIdentity)))
2296   {
2297     GNUNET_break_op (0);
2298     return;
2299   }
2300   if (ntohl (sdm->purpose.size) !=
2301       sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
2302       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) +
2303       sizeof (struct GNUNET_TIME_AbsoluteNBO))
2304   {
2305     GNUNET_break_op (0);
2306     return;
2307   }
2308   if (GNUNET_OK !=
2309       GNUNET_CRYPTO_rsa_verify
2310       (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT, &sdm->purpose,
2311        &sdm->signature, &sdm->public_key))
2312   {
2313     GNUNET_break_op (0);
2314     return;
2315   }
2316   GST_neighbours_force_disconnect (peer);
2317 }
2318
2319
2320 /**
2321  * We received a 'SESSION_CONNECT_ACK' message from the other peer.
2322  * Consider switching to it.
2323  *
2324  * @param message possibly a 'struct SessionConnectMessage' (check format)
2325  * @param peer identity of the peer to switch the address for
2326  * @param address address of the other peer, NULL if other peer
2327  *                       connected to us
2328  * @param session session to use (or NULL)
2329  * @param ats performance data
2330  * @param ats_count number of entries in ats
2331  */
2332 void
2333 GST_neighbours_handle_connect_ack (const struct GNUNET_MessageHeader *message,
2334                                    const struct GNUNET_PeerIdentity *peer,
2335                                    const struct GNUNET_HELLO_Address *address,
2336                                    struct Session *session,
2337                                    const struct GNUNET_ATS_Information *ats,
2338                                    uint32_t ats_count)
2339 {
2340   const struct SessionConnectMessage *scm;
2341   struct GNUNET_MessageHeader msg;
2342   struct NeighbourMapEntry *n;
2343   size_t msg_len;
2344   size_t ret;
2345
2346   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2347               "Received CONNECT_ACK message from peer `%s'\n",
2348               GNUNET_i2s (peer));
2349
2350   if (ntohs (message->size) != sizeof (struct SessionConnectMessage))
2351   {
2352     GNUNET_break_op (0);
2353     return;
2354   }
2355   scm = (const struct SessionConnectMessage *) message;
2356   GNUNET_break_op (ntohl (scm->reserved) == 0);
2357   n = lookup_neighbour (peer);
2358   if (NULL == n)
2359   {
2360     /* we did not send 'CONNECT' -- at least not recently */
2361     GNUNET_STATISTICS_update (GST_stats,
2362                               gettext_noop
2363                               ("# unexpected CONNECT_ACK messages (no peer)"),
2364                               1, GNUNET_NO);
2365     return;
2366   }
2367
2368   /* Additional check
2369    *
2370    * ((n->state != S_CONNECT_RECV) && (n->address != NULL)):
2371    *
2372    * We also received an CONNECT message, switched from SENDT to RECV and
2373    * ATS already suggested us an address after a successful blacklist check
2374    */
2375
2376   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2377               "Received CONNECT_ACK message from peer `%s' in state `%s'\n",
2378               GNUNET_i2s (peer),
2379               print_state(n->state));
2380
2381   if ((n->address != NULL) && (n->state == S_CONNECTED))
2382   {
2383     /* After fast reconnect: send ACK (ACK) even when we are connected */
2384     msg_len = sizeof (msg);
2385     msg.size = htons (msg_len);
2386     msg.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK);
2387
2388     ret = send_with_session(n,
2389               (const char *) &msg, msg_len,
2390               UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL,
2391               NULL, NULL);
2392
2393     if (ret == GNUNET_SYSERR)
2394       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2395                   "Failed to send SESSION_ACK to `%4s' using address '%s' session %X\n",
2396                   GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session);
2397     return;
2398   }
2399
2400   if ((n->state != S_CONNECT_SENT) &&
2401       ((n->state != S_CONNECT_RECV) && (n->address != NULL)))
2402   {
2403     GNUNET_STATISTICS_update (GST_stats,
2404                               gettext_noop
2405                               ("# unexpected CONNECT_ACK messages"), 1,
2406                               GNUNET_NO);
2407     return;
2408   }
2409   if (n->state != S_CONNECTED)
2410     change_state (n, S_CONNECTED);
2411
2412   if (NULL != session)
2413   {
2414     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2415                      "transport-ats",
2416                      "Giving ATS session %p of plugin %s for peer %s\n",
2417                      session, address->transport_name, GNUNET_i2s (peer));
2418   }
2419   GNUNET_ATS_address_update (GST_ats, address, session, ats, ats_count);
2420   GNUNET_assert (NULL != n->address);
2421
2422   if ((n->address_state == FRESH) && (0 == GNUNET_HELLO_address_cmp(address, n->address)))
2423   {
2424     GST_validation_set_address_use (n->address, n->session, GNUNET_YES);
2425     GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_YES);
2426     n->address_state = USED;
2427   }
2428
2429   GST_neighbours_set_incoming_quota (&n->id, n->bandwidth_in);
2430
2431   /* send ACK (ACK) */
2432   msg_len = sizeof (msg);
2433   msg.size = htons (msg_len);
2434   msg.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK);
2435
2436   ret = send_with_session(n,
2437             (const char *) &msg, msg_len,
2438             UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL,
2439             NULL, NULL);
2440
2441   if (ret == GNUNET_SYSERR)
2442     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2443                 "Failed to send SESSION_ACK to `%4s' using address '%s' session %X\n",
2444                 GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session);
2445
2446
2447   if (n->keepalive_task == GNUNET_SCHEDULER_NO_TASK)
2448     n->keepalive_task = GNUNET_SCHEDULER_add_now (&neighbour_keepalive_task, n);
2449
2450   neighbours_connected++;
2451   GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), 1,
2452                             GNUNET_NO);
2453 #if DEBUG_TRANSPORT
2454   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2455               "Notify about connect of `%4s' using address '%s' session %X LINE %u\n",
2456               GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session,
2457               __LINE__);
2458 #endif
2459   connect_notify_cb (callback_cls, &n->id, ats, ats_count);
2460   send_outbound_quota (peer, n->bandwidth_out);
2461
2462 }
2463
2464
2465 void
2466 GST_neighbours_handle_ack (const struct GNUNET_MessageHeader *message,
2467                            const struct GNUNET_PeerIdentity *peer,
2468                            const struct GNUNET_HELLO_Address *address,
2469                            struct Session *session,
2470                            const struct GNUNET_ATS_Information *ats,
2471                            uint32_t ats_count)
2472 {
2473   struct NeighbourMapEntry *n;
2474
2475 #if DEBUG_TRANSPORT
2476   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ACK message from peer `%s'\n",
2477               GNUNET_i2s (peer));
2478 #endif
2479
2480   if (ntohs (message->size) != sizeof (struct GNUNET_MessageHeader))
2481   {
2482     GNUNET_break_op (0);
2483     return;
2484   }
2485   n = lookup_neighbour (peer);
2486   if (NULL == n)
2487   {
2488     GNUNET_break (0);
2489     return;
2490   }
2491   if (S_CONNECTED == n->state)
2492     return;
2493   if (!is_connecting (n))
2494   {
2495     GNUNET_STATISTICS_update (GST_stats,
2496                               gettext_noop ("# unexpected ACK messages"), 1,
2497                               GNUNET_NO);
2498     return;
2499   }
2500   change_state (n, S_CONNECTED);
2501   if (NULL != session)
2502     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2503                      "transport-ats",
2504                      "Giving ATS session %p of plugin %s for peer %s\n",
2505                      session, address->transport_name, GNUNET_i2s (peer));
2506   GNUNET_ATS_address_update (GST_ats, address, session, ats, ats_count);
2507   GNUNET_assert (n->address != NULL);
2508
2509   if ((n->address_state == FRESH) && (0 == GNUNET_HELLO_address_cmp(address, n->address)))
2510   {
2511     GST_validation_set_address_use (n->address, n->session, GNUNET_YES);
2512     GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_YES);
2513     n->address_state = USED;
2514   }
2515
2516
2517   neighbours_connected++;
2518   GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), 1,
2519                             GNUNET_NO);
2520
2521   GST_neighbours_set_incoming_quota (&n->id, n->bandwidth_in);
2522   if (n->keepalive_task == GNUNET_SCHEDULER_NO_TASK)
2523     n->keepalive_task = GNUNET_SCHEDULER_add_now (&neighbour_keepalive_task, n);
2524 #if DEBUG_TRANSPORT
2525   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2526               "Notify about connect of `%4s' using address '%s' session %X LINE %u\n",
2527               GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session,
2528               __LINE__);
2529 #endif
2530   connect_notify_cb (callback_cls, &n->id, ats, ats_count);
2531   send_outbound_quota (peer, n->bandwidth_out);
2532 }
2533
2534 struct BlackListCheckContext
2535 {
2536   struct GNUNET_ATS_Information *ats;
2537
2538   uint32_t ats_count;
2539
2540   struct Session *session;
2541
2542   struct GNUNET_HELLO_Address *address;
2543
2544   struct GNUNET_TIME_Absolute ts;
2545 };
2546
2547
2548 static void
2549 handle_connect_blacklist_cont (void *cls,
2550                                const struct GNUNET_PeerIdentity *peer,
2551                                int result)
2552 {
2553   struct NeighbourMapEntry *n;
2554   struct BlackListCheckContext *bcc = cls;
2555
2556 #if DEBUG_TRANSPORT
2557   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2558               "Blacklist check due to CONNECT message: `%s'\n",
2559               GNUNET_i2s (peer),
2560               (result == GNUNET_OK) ? "ALLOWED" : "FORBIDDEN");
2561 #endif
2562
2563   /* not allowed */
2564   if (GNUNET_OK != result)
2565   {
2566     GNUNET_HELLO_address_free (bcc->address);
2567     GNUNET_free (bcc);
2568     return;
2569   }
2570
2571   n = lookup_neighbour (peer);
2572   if (NULL == n)
2573     n = setup_neighbour (peer);
2574
2575   if (bcc->ts.abs_value > n->connect_ts.abs_value)
2576   {
2577     if (NULL != bcc->session)
2578       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2579                        "transport-ats",
2580                        "Giving ATS session %p of address `%s' for peer %s\n",
2581                        bcc->session, GST_plugins_a2s (bcc->address),
2582                        GNUNET_i2s (peer));
2583     /* Tell ATS about the session, so ATS can suggest it if it likes it. */
2584
2585     GNUNET_ATS_address_update (GST_ats, bcc->address, bcc->session, bcc->ats,
2586                                bcc->ats_count);
2587     n->connect_ts = bcc->ts;
2588   }
2589
2590   GNUNET_HELLO_address_free (bcc->address);
2591   GNUNET_free (bcc);
2592
2593   if (n->state != S_CONNECT_RECV)
2594     change_state (n, S_CONNECT_RECV);
2595
2596
2597   /* Ask ATS for an address to connect via that address */
2598   if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
2599     GNUNET_SCHEDULER_cancel (n->ats_suggest);
2600   n->ats_suggest =
2601       GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel,
2602                                     n);
2603   GNUNET_ATS_suggest_address (GST_ats, peer);
2604 }
2605
2606 /**
2607  * We received a 'SESSION_CONNECT' message from the other peer.
2608  * Consider switching to it.
2609  *
2610  * @param message possibly a 'struct SessionConnectMessage' (check format)
2611  * @param peer identity of the peer to switch the address for
2612  * @param address address of the other peer, NULL if other peer
2613  *                       connected to us
2614  * @param session session to use (or NULL)
2615  * @param ats performance data
2616  * @param ats_count number of entries in ats (excluding 0-termination)
2617  */
2618 void
2619 GST_neighbours_handle_connect (const struct GNUNET_MessageHeader *message,
2620                                const struct GNUNET_PeerIdentity *peer,
2621                                const struct GNUNET_HELLO_Address *address,
2622                                struct Session *session,
2623                                const struct GNUNET_ATS_Information *ats,
2624                                uint32_t ats_count)
2625 {
2626   const struct SessionConnectMessage *scm;
2627   struct BlackListCheckContext *bcc = NULL;
2628   struct NeighbourMapEntry *n;
2629
2630 #if DEBUG_TRANSPORT
2631   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2632               "Received CONNECT message from peer `%s'\n", GNUNET_i2s (peer));
2633 #endif
2634
2635   if (ntohs (message->size) != sizeof (struct SessionConnectMessage))
2636   {
2637     GNUNET_break_op (0);
2638     return;
2639   }
2640
2641   scm = (const struct SessionConnectMessage *) message;
2642   GNUNET_break_op (ntohl (scm->reserved) == 0);
2643
2644   GNUNET_ATS_address_update (GST_ats, address, session, ats, ats_count);
2645
2646   n = lookup_neighbour (peer);
2647   if ((n != NULL) && ((S_CONNECTED == n->state) || (S_FAST_RECONNECT == n->state)))
2648   {
2649     /* connected peer switches addresses or is trying to do a fast reconnect*/
2650     return;
2651   }
2652
2653
2654   /* we are not connected to this peer */
2655   /* do blacklist check */
2656   bcc =
2657       GNUNET_malloc (sizeof (struct BlackListCheckContext) +
2658                      sizeof (struct GNUNET_ATS_Information) * (ats_count + 1));
2659   bcc->ts = GNUNET_TIME_absolute_ntoh (scm->timestamp);
2660   bcc->ats_count = ats_count + 1;
2661   bcc->address = GNUNET_HELLO_address_copy (address);
2662   bcc->session = session;
2663   bcc->ats = (struct GNUNET_ATS_Information *) &bcc[1];
2664   memcpy (bcc->ats, ats, sizeof (struct GNUNET_ATS_Information) * ats_count);
2665   bcc->ats[ats_count].type = htonl (GNUNET_ATS_QUALITY_NET_DELAY);
2666   bcc->ats[ats_count].value =
2667       htonl ((uint32_t) GST_neighbour_get_latency (peer).rel_value);
2668   GST_blacklist_test_allowed (peer, address->transport_name,
2669                               &handle_connect_blacklist_cont, bcc);
2670 }
2671
2672
2673 /* end of file gnunet-service-transport_neighbours.c */