(no commit message)
[oweals/gnunet.git] / src / transport / gnunet-service-transport_neighbours_3way.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?
52  * (idle timeout is 5 minutes or 300 seconds, so with 90s interval we
53  * send 3 keepalives in each interval, so 3 messages would need to be
54  * lost in a row for a disconnect).
55  */
56 #define KEEPALIVE_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 90)
57
58
59 /**
60  * Entry in neighbours.
61  */
62 struct NeighbourMapEntry;
63
64 /**
65  * Message a peer sends to another to indicate its
66  * preference for communicating via a particular
67  * session (and the desire to establish a real
68  * connection).
69  */
70 struct SessionConnectMessage
71 {
72   /**
73    * Header of type 'GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT'
74    */
75   struct GNUNET_MessageHeader header;
76
77   /**
78    * Always zero.
79    */
80   uint32_t reserved GNUNET_PACKED;
81
82   /**
83    * Absolute time at the sender.  Only the most recent connect
84    * message implies which session is preferred by the sender.
85    */
86   struct GNUNET_TIME_AbsoluteNBO timestamp;
87
88 };
89
90
91 struct SessionDisconnectMessage
92 {
93   /**
94    * Header of type 'GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT'
95    */
96   struct GNUNET_MessageHeader header;
97
98   /**
99    * Always zero.
100    */
101   uint32_t reserved GNUNET_PACKED;
102
103   /**
104    * Purpose of the signature.  Extends over the timestamp.
105    * Purpose should be GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DISCONNECT.
106    */
107   struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
108
109   /**
110    * Absolute time at the sender.  Only the most recent connect
111    * message implies which session is preferred by the sender.
112    */
113   struct GNUNET_TIME_AbsoluteNBO timestamp;
114
115   /**
116    * Public key of the sender.
117    */
118   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
119   
120   /**
121    * Signature of the peer that sends us the disconnect.  Only
122    * valid if the timestamp is AFTER the timestamp from the
123    * corresponding 'CONNECT' message.
124    */
125   struct GNUNET_CRYPTO_RsaSignature signature;
126
127 };
128
129
130 /**
131  * For each neighbour we keep a list of messages
132  * that we still want to transmit to the neighbour.
133  */
134 struct MessageQueue
135 {
136
137   /**
138    * This is a doubly linked list.
139    */
140   struct MessageQueue *next;
141
142   /**
143    * This is a doubly linked list.
144    */
145   struct MessageQueue *prev;
146
147   /**
148    * Once this message is actively being transmitted, which
149    * neighbour is it associated with?
150    */
151   struct NeighbourMapEntry *n;
152
153   /**
154    * Function to call once we're done.
155    */
156   GST_NeighbourSendContinuation cont;
157
158   /**
159    * Closure for 'cont'
160    */
161   void *cont_cls;
162
163   /**
164    * The message(s) we want to transmit, GNUNET_MessageHeader(s)
165    * stuck together in memory.  Allocated at the end of this struct.
166    */
167   const char *message_buf;
168
169   /**
170    * Size of the message buf
171    */
172   size_t message_buf_size;
173
174   /**
175    * At what time should we fail?
176    */
177   struct GNUNET_TIME_Absolute timeout;
178
179 };
180
181 enum State
182 {
183     /* fresh peer or completely disconnected */
184     S_NOT_CONNECTED = 0,
185     /* sent CONNECT message to other peer, waiting for CONNECT_ACK */
186     S_CONNECT_SENT = 1,
187     /* received CONNECT message to other peer, sending CONNECT_ACK */
188     S_CONNECT_RECV = 4,
189     /* sent CONNECT_ACK message to other peer, wait for ACK or payload */
190     S_CONNECT_RECV_ACK_SENT = 8,
191     /* received ACK or payload */
192     S_CONNECTED = 16,
193     /* Disconnect in progress */
194     S_DISCONNECT = 32
195 };
196
197 /**
198  * Entry in neighbours.
199  */
200 struct NeighbourMapEntry
201 {
202
203   /**
204    * Head of list of messages we would like to send to this peer;
205    * must contain at most one message per client.
206    */
207   struct MessageQueue *messages_head;
208
209   /**
210    * Tail of list of messages we would like to send to this peer; must
211    * contain at most one message per client.
212    */
213   struct MessageQueue *messages_tail;
214
215   /**
216    * Performance data for the peer.
217    */
218   //struct GNUNET_ATS_Information *ats;
219
220   /**
221    * Are we currently trying to send a message? If so, which one?
222    */
223   struct MessageQueue *is_active;
224
225   /**
226    * Active session for communicating with the peer.
227    */
228   struct Session *session;
229
230   /**
231    * Name of the plugin we currently use.
232    */
233   char *plugin_name;
234
235   /**
236    * Address used for communicating with the peer, NULL for inbound connections.
237    */
238   void *addr;
239
240   /**
241    * Number of bytes in 'addr'.
242    */
243   size_t addrlen;
244
245   /**
246    * Identity of this neighbour.
247    */
248   struct GNUNET_PeerIdentity id;
249
250   /**
251    * ID of task scheduled to run when this peer is about to
252    * time out (will free resources associated with the peer).
253    */
254   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
255
256   /**
257    * ID of task scheduled to send keepalives.
258    */
259   GNUNET_SCHEDULER_TaskIdentifier keepalive_task;
260
261   /**
262    * ID of task scheduled to run when we should try transmitting
263    * the head of the message queue.
264    */
265   GNUNET_SCHEDULER_TaskIdentifier transmission_task;
266
267   /**
268    * Tracker for inbound bandwidth.
269    */
270   struct GNUNET_BANDWIDTH_Tracker in_tracker;
271
272   /**
273    * Inbound bandwidth from ATS, activated when connection is up
274    */
275   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
276
277   /**
278    * Inbound bandwidth from ATS, activated when connection is up
279    */
280   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
281
282   /**
283    * Timestamp of the 'SESSION_CONNECT' message we got from the other peer
284    */
285   struct GNUNET_TIME_Absolute connect_ts;
286
287   /**
288    * How often has the other peer (recently) violated the inbound
289    * traffic limit?  Incremented by 10 per violation, decremented by 1
290    * per non-violation (for each time interval).
291    */
292   unsigned int quota_violation_count;
293
294   /**
295    * Number of values in 'ats' array.
296    */
297   //unsigned int ats_count;
298
299
300   /**
301    * Do we currently consider this neighbour connected? (as far as
302    * the connect/disconnect callbacks are concerned)?
303    */
304   //int is_connected;
305
306   int state;
307
308 };
309
310
311 /**
312  * All known neighbours and their HELLOs.
313  */
314 static struct GNUNET_CONTAINER_MultiHashMap *neighbours;
315
316 /**
317  * Closure for connect_notify_cb and disconnect_notify_cb
318  */
319 static void *callback_cls;
320
321 /**
322  * Function to call when we connected to a neighbour.
323  */
324 static GNUNET_TRANSPORT_NotifyConnect connect_notify_cb;
325
326 /**
327  * Function to call when we disconnected from a neighbour.
328  */
329 static GNUNET_TRANSPORT_NotifyDisconnect disconnect_notify_cb;
330
331 /**
332  * counter for connected neighbours
333  */
334 static int neighbours_connected;
335
336 /**
337  * Lookup a neighbour entry in the neighbours hash map.
338  *
339  * @param pid identity of the peer to look up
340  * @return the entry, NULL if there is no existing record
341  */
342 static struct NeighbourMapEntry *
343 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
344 {
345   return GNUNET_CONTAINER_multihashmap_get (neighbours, &pid->hashPubKey);
346 }
347
348 #define change_state(n, state, ...) change (n, state, __LINE__)
349
350 static int
351 is_connecting (struct NeighbourMapEntry * n)
352 {
353   if ((n->state > S_NOT_CONNECTED) && (n->state < S_CONNECTED))
354     return GNUNET_YES;
355   return GNUNET_NO;
356 }
357
358 static int
359 is_connected (struct NeighbourMapEntry * n)
360 {
361   if (n->state == S_CONNECTED)
362     return GNUNET_YES;
363   return GNUNET_NO;
364 }
365
366 static int
367 is_disconnecting (struct NeighbourMapEntry * n)
368 {
369   if (n->state == S_DISCONNECT)
370     return GNUNET_YES;
371   return GNUNET_NO;
372 }
373
374 static const char *
375 print_state (int state)
376 {
377   switch (state) {
378     case S_CONNECTED:
379         return "S_CONNECTED";
380       break;
381     case S_CONNECT_RECV:
382       return "S_CONNECT_RECV";
383       break;
384     case S_CONNECT_RECV_ACK_SENT:
385       return"S_CONNECT_RECV_ACK_SENT";
386       break;
387     case S_CONNECT_SENT:
388       return "S_CONNECT_SENT";
389       break;
390     case S_DISCONNECT:
391       return "S_DISCONNECT";
392       break;
393     case S_NOT_CONNECTED:
394       return "S_NOT_CONNECTED";
395       break;
396     default:
397       GNUNET_break (0);
398       break;
399   }
400   return NULL;
401 }
402
403 static int
404 change (struct NeighbourMapEntry * n, int state, int line)
405 {
406   char * old = strdup(print_state(n->state));
407   char * new = strdup(print_state(state));
408
409   /* allowed transitions */
410   int allowed = GNUNET_NO;
411   switch (n->state) {
412   case S_NOT_CONNECTED:
413     if ((state == S_CONNECT_RECV) || (state == S_CONNECT_SENT) ||
414         (state == S_DISCONNECT))
415     {
416       allowed = GNUNET_YES;
417       break;
418     }
419     break;
420   case S_CONNECT_RECV:
421     if ((state == S_NOT_CONNECTED) || (state == S_DISCONNECT) ||
422         (state == S_CONNECTED))
423     {
424       allowed = GNUNET_YES;
425       break;
426     }
427     break;
428   case S_CONNECT_SENT:
429     if ((state == S_NOT_CONNECTED) || (state == S_CONNECTED) ||
430         (state == S_DISCONNECT) || /* FIXME SENT -> RECV ISSUE!*/ (state == S_CONNECT_RECV))
431     {
432       allowed = GNUNET_YES;
433       break;
434     }
435     break;
436   case S_CONNECTED:
437     if (state == S_DISCONNECT)
438     {
439       allowed = GNUNET_YES;
440       break;
441     }
442     break;
443   case S_DISCONNECT:
444     /*
445     if (state == S_NOT_CONNECTED)
446     {
447       allowed = GNUNET_YES;
448       break;
449     }*/
450     break;
451   default:
452     GNUNET_break (0);
453     break;
454
455   }
456
457   if (allowed == GNUNET_NO)
458   {
459     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
460         "Illegal state transition from `%s' to `%s' in line %u \n",
461         old, new, line);
462     GNUNET_break (0);
463     GNUNET_free (old);
464     GNUNET_free (new);
465     return GNUNET_SYSERR;
466   }
467
468   n->state = state;
469   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "State for neighbour `%s' %X changed from `%s' to `%s' in line %u\n",
470       GNUNET_i2s (&n->id), n, old, new, line);
471   GNUNET_free (old);
472   GNUNET_free (new);
473   return GNUNET_OK;
474 }
475
476 static ssize_t
477 send_with_plugin ( const struct GNUNET_PeerIdentity * target,
478     const char *msgbuf,
479     size_t msgbuf_size,
480     uint32_t priority,
481     struct GNUNET_TIME_Relative timeout,
482     struct Session * session,
483     const char * plugin_name,
484     const void *addr,
485     size_t addrlen,
486     int force_address,
487     GNUNET_TRANSPORT_TransmitContinuation cont,
488     void *cont_cls)
489
490 {
491   struct GNUNET_TRANSPORT_PluginFunctions *papi;
492   size_t ret = GNUNET_SYSERR;
493
494   papi = GST_plugins_find (plugin_name);
495   if (papi == NULL)
496   {
497     if (cont != NULL)
498       cont (cont_cls, target, GNUNET_SYSERR);
499     return GNUNET_SYSERR;
500   }
501
502   ret = papi->send (papi->cls,
503       target,
504       msgbuf, msgbuf_size,
505       0,
506       timeout,
507       session,
508       addr, addrlen,
509       GNUNET_YES,
510       cont, cont_cls);
511
512   if (ret == -1)
513   {
514     if (cont != NULL)
515       cont (cont_cls, target, GNUNET_SYSERR);
516   }
517   return ret;
518 }
519
520 /**
521  * Task invoked to start a transmission to another peer.
522  *
523  * @param cls the 'struct NeighbourMapEntry'
524  * @param tc scheduler context
525  */
526 static void
527 transmission_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
528
529
530 /**
531  * We're done with our transmission attempt, continue processing.
532  *
533  * @param cls the 'struct MessageQueue' of the message
534  * @param receiver intended receiver
535  * @param success whether it worked or not
536  */
537 static void
538 transmit_send_continuation (void *cls,
539                             const struct GNUNET_PeerIdentity *receiver,
540                             int success)
541 {
542   struct MessageQueue *mq;
543   struct NeighbourMapEntry *n;
544
545   mq = cls;
546   n = mq->n;
547   if (NULL != n)
548   {
549     GNUNET_assert (n->is_active == mq);
550     n->is_active = NULL;
551     if (success == GNUNET_YES)
552     {
553       GNUNET_assert (n->transmission_task == GNUNET_SCHEDULER_NO_TASK);
554       n->transmission_task = GNUNET_SCHEDULER_add_now (&transmission_task, n);
555     }
556   }
557 #if DEBUG_TRANSPORT
558   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message of type %u was %s\n",
559               ntohs (((struct GNUNET_MessageHeader *) mq->message_buf)->type),
560               (success == GNUNET_OK) ? "successful" : "FAILED");
561 #endif
562   if (NULL != mq->cont)
563     mq->cont (mq->cont_cls, success);
564   GNUNET_free (mq);
565 }
566
567
568 /**
569  * Check the ready list for the given neighbour and if a plugin is
570  * ready for transmission (and if we have a message), do so!
571  *
572  * @param n target peer for which to transmit
573  */
574 static void
575 try_transmission_to_peer (struct NeighbourMapEntry *n)
576 {
577   struct MessageQueue *mq;
578   struct GNUNET_TIME_Relative timeout;
579   ssize_t ret;
580
581   if (n->is_active != NULL)
582   {
583     GNUNET_break (0);
584     return;                     /* transmission already pending */
585   }
586   if (n->transmission_task != GNUNET_SCHEDULER_NO_TASK)
587   {
588     GNUNET_break (0);
589     return;                     /* currently waiting for bandwidth */
590   }
591   while (NULL != (mq = n->messages_head))
592   {
593     timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
594     if (timeout.rel_value > 0)
595       break;
596     GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
597     n->is_active = mq;
598     mq->n = n;
599     transmit_send_continuation (mq, &n->id, GNUNET_SYSERR);     /* timeout */
600   }
601   if (NULL == mq)
602     return;                     /* no more messages */
603
604   if (GST_plugins_find (n->plugin_name) == NULL)
605   {
606     GNUNET_break (0);
607     return;
608   }
609   GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
610   n->is_active = mq;
611   mq->n = n;
612
613   if  ((n->session == NULL) && (n->addr == NULL) && (n->addrlen == 0))
614   {
615     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No address for peer `%s'\n",
616                 GNUNET_i2s (&n->id));
617     transmit_send_continuation (mq, &n->id, GNUNET_SYSERR);
618     GNUNET_assert (n->transmission_task == GNUNET_SCHEDULER_NO_TASK);
619     n->transmission_task = GNUNET_SCHEDULER_add_now (&transmission_task, n);
620     return;
621   }
622
623   ret = send_with_plugin (&n->id,
624                           mq->message_buf, mq->message_buf_size, 0,
625                           timeout,
626                           n->session, n->plugin_name, n->addr, n->addrlen,
627                           GNUNET_YES,
628                           &transmit_send_continuation, mq);
629   if (ret == -1)
630   {
631     /* failure, but 'send' would not call continuation in this case,
632      * so we need to do it here! */
633     transmit_send_continuation (mq, &n->id, GNUNET_SYSERR);
634   }
635
636 }
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   struct NeighbourMapEntry *n = cls;
649   GNUNET_assert (NULL != lookup_neighbour(&n->id));
650   n->transmission_task = GNUNET_SCHEDULER_NO_TASK;
651   try_transmission_to_peer (n);
652 }
653
654
655 /**
656  * Initialize the neighbours subsystem.
657  *
658  * @param cls closure for callbacks
659  * @param connect_cb function to call if we connect to a peer
660  * @param disconnect_cb function to call if we disconnect from a peer
661  */
662 void
663 GST_neighbours_start (void *cls, GNUNET_TRANSPORT_NotifyConnect connect_cb,
664                       GNUNET_TRANSPORT_NotifyDisconnect disconnect_cb)
665 {
666   callback_cls = cls;
667   connect_notify_cb = connect_cb;
668   disconnect_notify_cb = disconnect_cb;
669   neighbours = GNUNET_CONTAINER_multihashmap_create (NEIGHBOUR_TABLE_SIZE);
670 }
671
672 /*
673 static void
674 send_disconnect_cont (void *cls,
675     const struct GNUNET_PeerIdentity * target,
676     int result)
677 {
678   struct NeighbourMapEntry *n = cls;
679
680 }*/
681
682 static int
683 send_disconnect (struct NeighbourMapEntry *n)
684 {
685   size_t ret;
686   struct SessionDisconnectMessage disconnect_msg;
687
688 #if DEBUG_TRANSPORT
689   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending DISCONNECT message to peer `%4s'\n",
690               GNUNET_i2s (&n->id));
691 #endif
692
693   disconnect_msg.header.size = htons (sizeof (struct SessionDisconnectMessage));
694   disconnect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
695   disconnect_msg.reserved = htonl (0);
696   disconnect_msg.purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
697                                        sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) +
698                                        sizeof (struct GNUNET_TIME_AbsoluteNBO) );
699   disconnect_msg.purpose.purpose = htonl (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT);
700   disconnect_msg.timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
701   disconnect_msg.public_key = GST_my_public_key;
702   GNUNET_assert (GNUNET_OK ==
703                  GNUNET_CRYPTO_rsa_sign (GST_my_private_key,
704                                          &disconnect_msg.purpose,
705                                          &disconnect_msg.signature));
706
707   ret = send_with_plugin(&n->id,
708       (const char *) &disconnect_msg, sizeof (disconnect_msg),
709       UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL, n->session, n->plugin_name, n->addr, n->addrlen,
710       GNUNET_YES, NULL, NULL);
711
712   if (ret == GNUNET_SYSERR)
713     return GNUNET_SYSERR;
714
715   GNUNET_STATISTICS_update (GST_stats,
716                             gettext_noop ("# peers disconnected due to external request"), 1,
717                             GNUNET_NO);
718   return GNUNET_OK;
719 }
720
721 /**
722  * Disconnect from the given neighbour, clean up the record.
723  *
724  * @param n neighbour to disconnect from
725  */
726 static void
727 disconnect_neighbour (struct NeighbourMapEntry *n)
728 {
729   struct MessageQueue *mq;
730   int was_connected = is_connected(n);
731
732   if (is_disconnecting(n) == GNUNET_YES)
733     return;
734
735   /* send DISCONNECT MESSAGE */
736   if (is_connected(n) || is_connecting(n))
737   {
738     if (GNUNET_OK == send_disconnect(n))
739       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent DISCONNECT_MSG to `%s'\n",
740                   GNUNET_i2s (&n->id));
741     else
742       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Could not send DISCONNECT_MSG to `%s'\n",
743                   GNUNET_i2s (&n->id));
744   }
745
746
747   if (is_disconnecting(n))
748     return;
749   change_state (n, S_DISCONNECT);
750
751   while (NULL != (mq = n->messages_head))
752   {
753     GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
754     if (NULL != mq->cont)
755       mq->cont (mq->cont_cls, GNUNET_SYSERR);
756     GNUNET_free (mq);
757   }
758   if (NULL != n->is_active)
759   {
760     n->is_active->n = NULL;
761     n->is_active = NULL;
762   }
763   if (was_connected)
764   {
765     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != n->keepalive_task);
766     GNUNET_SCHEDULER_cancel (n->keepalive_task);
767     n->keepalive_task = GNUNET_SCHEDULER_NO_TASK;  
768     GNUNET_assert (neighbours_connected > 0);
769     neighbours_connected--;
770     GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), -1,
771                               GNUNET_NO);
772     disconnect_notify_cb (callback_cls, &n->id);
773   }
774   GNUNET_assert (GNUNET_YES ==
775                  GNUNET_CONTAINER_multihashmap_remove (neighbours,
776                                                        &n->id.hashPubKey, n));
777   if (GNUNET_SCHEDULER_NO_TASK != n->timeout_task)
778   {
779     GNUNET_SCHEDULER_cancel (n->timeout_task);
780     n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
781   }
782   if (GNUNET_SCHEDULER_NO_TASK != n->transmission_task)
783   {
784     GNUNET_SCHEDULER_cancel (n->transmission_task);
785     n->transmission_task = GNUNET_SCHEDULER_NO_TASK;
786   }
787   if (NULL != n->plugin_name)
788   {
789     GNUNET_free (n->plugin_name);
790     n->plugin_name = NULL;
791   }
792   if (NULL != n->addr)
793   {
794     GNUNET_free (n->addr);
795     n->addr = NULL;
796     n->addrlen = 0;
797   }
798   n->session = NULL;
799   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting peer `%4s', %X\n",
800               GNUNET_i2s (&n->id), n);
801   GNUNET_free (n);
802 }
803
804
805 /**
806  * Peer has been idle for too long. Disconnect.
807  *
808  * @param cls the 'struct NeighbourMapEntry' of the neighbour that went idle
809  * @param tc scheduler context
810  */
811 static void
812 neighbour_timeout_task (void *cls,
813                         const struct GNUNET_SCHEDULER_TaskContext *tc)
814 {
815   struct NeighbourMapEntry *n = cls;
816
817   n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
818
819   GNUNET_STATISTICS_update (GST_stats,
820                             gettext_noop ("# peers disconnected due to timeout"), 1,
821                             GNUNET_NO);
822   disconnect_neighbour (n);
823 }
824
825
826 /**
827  * Send another keepalive message.
828  *
829  * @param cls the 'struct NeighbourMapEntry' of the neighbour that went idle
830  * @param tc scheduler context
831  */
832 static void
833 neighbour_keepalive_task (void *cls,
834                           const struct GNUNET_SCHEDULER_TaskContext *tc)
835 {
836   struct NeighbourMapEntry *n = cls;
837   struct GNUNET_MessageHeader m;
838
839   n->keepalive_task = GNUNET_SCHEDULER_add_delayed (KEEPALIVE_FREQUENCY,
840                                                     &neighbour_keepalive_task,
841                                                     n);
842   GNUNET_assert (is_connected(n));
843   GNUNET_STATISTICS_update (GST_stats,
844                             gettext_noop ("# keepalives sent"), 1,
845                             GNUNET_NO);
846   m.size = htons (sizeof (struct GNUNET_MessageHeader));
847   m.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE);
848
849   send_with_plugin(&n->id, (const void *) &m,
850                    sizeof (m),
851                    UINT32_MAX /* priority */ ,
852                    GNUNET_TIME_UNIT_FOREVER_REL,
853                    n->session, n->plugin_name, n->addr, n->addrlen,
854                    GNUNET_YES, NULL, NULL);
855 }
856
857
858 /**
859  * Disconnect from the given neighbour.
860  *
861  * @param cls unused
862  * @param key hash of neighbour's public key (not used)
863  * @param value the 'struct NeighbourMapEntry' of the neighbour
864  */
865 static int
866 disconnect_all_neighbours (void *cls, const GNUNET_HashCode * key, void *value)
867 {
868   struct NeighbourMapEntry *n = value;
869
870 #if DEBUG_TRANSPORT
871   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s', %s\n",
872               GNUNET_i2s (&n->id), "SHUTDOWN_TASK");
873 #endif
874   if (is_connected(n))
875     GNUNET_STATISTICS_update (GST_stats,
876                               gettext_noop ("# peers disconnected due to global disconnect"), 1,
877                               GNUNET_NO);
878   disconnect_neighbour (n);
879   return GNUNET_OK;
880 }
881
882
883 /**
884  * Cleanup the neighbours subsystem.
885  */
886 void
887 GST_neighbours_stop ()
888 {
889   GNUNET_assert (neighbours != NULL);
890
891   GNUNET_CONTAINER_multihashmap_iterate (neighbours, &disconnect_all_neighbours,
892                                          NULL);
893   GNUNET_CONTAINER_multihashmap_destroy (neighbours);
894   GNUNET_assert (neighbours_connected == 0);
895   neighbours = NULL;
896   callback_cls = NULL;
897   connect_notify_cb = NULL;
898   disconnect_notify_cb = NULL;
899 }
900
901
902 /**
903  * We tried to send a SESSION_CONNECT message to another peer.  If this
904  * succeeded, we change the state.  If it failed, we should tell
905  * ATS to not use this address anymore (until it is re-validated).
906  *
907  * @param cls the 'struct NeighbourMapEntry'
908  * @param success GNUNET_OK on success
909  */
910 static void
911 send_connect_continuation (void *cls,
912       const struct GNUNET_PeerIdentity * target,
913       int success)
914
915 {
916   struct NeighbourMapEntry *n = cls;
917
918   GNUNET_assert (n != NULL);
919   GNUNET_assert (!is_connected(n));
920
921   if (is_disconnecting(n))
922     return; /* neighbour is going away */
923   if (GNUNET_YES != success)
924   {
925 #if DEBUG_TRANSPORT
926     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
927               "Failed to send CONNECT_MSG to peer `%4s' with plugin `%s' address '%s' session %X, asking ATS for new address \n",
928               GNUNET_i2s (&n->id), n->plugin_name,
929               (n->addrlen == 0) ? "<inbound>" : GST_plugins_a2s (n->plugin_name,
930                                                                   n->addr,
931                                                                   n->addrlen),
932               n->session);
933 #endif
934
935     GNUNET_ATS_address_destroyed (GST_ats,
936                                   &n->id,
937                                   n->plugin_name, 
938                                   n->addr,
939                                   n->addrlen,
940                                   NULL);
941
942     GNUNET_ATS_suggest_address(GST_ats, &n->id);
943     return;
944   }
945   change_state(n, S_CONNECT_SENT);
946 }
947
948
949 /**
950  * We tried to switch addresses with an peer already connected. If it failed,
951  * we should tell ATS to not use this address anymore (until it is re-validated).
952  *
953  * @param cls the 'struct NeighbourMapEntry'
954  * @param success GNUNET_OK on success
955  */
956 static void
957 send_switch_address_continuation (void *cls,
958       const struct GNUNET_PeerIdentity * target,
959       int success)
960
961 {
962   struct NeighbourMapEntry *n = cls;
963
964   GNUNET_assert (n != NULL);
965   if (is_disconnecting(n))
966     return; /* neighbour is going away */
967
968   GNUNET_assert (n->state == S_CONNECTED);
969   if (GNUNET_YES != success)
970   {
971 #if DEBUG_TRANSPORT
972     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
973               "Failed to switch connected peer `%s' to plugin `%s' address '%s' session %X, asking ATS for new address \n",
974               GNUNET_i2s (&n->id), n->plugin_name,
975               (n->addrlen == 0) ? "<inbound>" : GST_plugins_a2s (n->plugin_name,
976                                                                   n->addr,
977                                                                   n->addrlen),
978               n->session);
979 #endif
980
981     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Do not forget to fix this!\n");
982     /* FIXME: We have to change the state away from connected:
983      * If ATS can not suggest another address we do not get a callback
984      * but we still think we are connected
985      */
986     //change_state(n, S_NOT_CONNECTED);
987
988     GNUNET_ATS_address_destroyed (GST_ats,
989                                   &n->id,
990                                   n->plugin_name,
991                                   n->addr,
992                                   n->addrlen,
993                                   NULL);
994
995     GNUNET_ATS_suggest_address(GST_ats, &n->id);
996     return;
997   }
998 }
999
1000 /**
1001  * We tried to send a SESSION_CONNECT message to another peer.  If this
1002  * succeeded, we change the state.  If it failed, we should tell
1003  * ATS to not use this address anymore (until it is re-validated).
1004  *
1005  * @param cls the 'struct NeighbourMapEntry'
1006  * @param success GNUNET_OK on success
1007  */
1008 static void
1009 send_connect_ack_continuation (void *cls,
1010       const struct GNUNET_PeerIdentity * target,
1011       int success)
1012
1013 {
1014   struct NeighbourMapEntry *n = cls;
1015
1016   GNUNET_assert (n != NULL);
1017
1018   if (GNUNET_YES == success)
1019     return; /* sending successful */
1020
1021   /* sending failed, ask for next address  */
1022 #if DEBUG_TRANSPORT
1023     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1024               "Failed to send CONNECT_MSG to peer `%4s' with plugin `%s' address '%s' session %X, asking ATS for new address \n",
1025               GNUNET_i2s (&n->id), n->plugin_name,
1026               (n->addrlen == 0) ? "<inbound>" : GST_plugins_a2s (n->plugin_name,
1027                                                                   n->addr,
1028                                                                   n->addrlen),
1029               n->session);
1030 #endif
1031     change_state(n, S_NOT_CONNECTED);
1032
1033     GNUNET_ATS_address_destroyed (GST_ats,
1034                                   &n->id,
1035                                   n->plugin_name,
1036                                   n->addr,
1037                                   n->addrlen,
1038                                   NULL);
1039
1040     GNUNET_ATS_suggest_address(GST_ats, &n->id);
1041 }
1042
1043 /**
1044  * For an existing neighbour record, set the active connection to
1045  * the given address.
1046  *
1047  * @param peer identity of the peer to switch the address for
1048  * @param plugin_name name of transport that delivered the PONG
1049  * @param address address of the other peer, NULL if other peer
1050  *                       connected to us
1051  * @param address_len number of bytes in address
1052  * @param session session to use (or NULL)
1053  * @param ats performance data
1054  * @param ats_count number of entries in ats
1055  * @return GNUNET_YES if we are currently connected, GNUNET_NO if the
1056  *         connection is not up (yet)
1057  */
1058 int
1059 GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer,
1060                                   const char *plugin_name, const void *address,
1061                                   size_t address_len, struct Session *session,
1062                                   const struct GNUNET_ATS_Information
1063                                   *ats, uint32_t ats_count,
1064                                   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
1065                                   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
1066 {
1067   struct NeighbourMapEntry *n;
1068   struct SessionConnectMessage connect_msg;
1069   size_t msg_len;
1070   size_t ret;
1071
1072   GNUNET_assert (neighbours != NULL);
1073   n = lookup_neighbour (peer);
1074   if (NULL == n)
1075   {
1076     if (NULL == session)
1077       GNUNET_ATS_address_destroyed (GST_ats,
1078                                     peer,
1079                                     plugin_name, address,
1080                                     address_len, NULL);    
1081     return GNUNET_NO;
1082   }
1083
1084 #if DEBUG_TRANSPORT
1085   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1086               "ATS tells us to switch to plugin `%s' address '%s' session %X for %s peer `%s'\n",
1087               plugin_name,
1088               (address_len == 0) ? "<inbound>" : GST_plugins_a2s (plugin_name,
1089                                                                   address,
1090                                                                   address_len),
1091               session, (is_connected(n) ? "CONNECTED" : "NOT CONNECTED"),
1092               GNUNET_i2s (peer));
1093 #endif
1094
1095   GNUNET_free_non_null (n->addr);
1096   n->addr = GNUNET_malloc (address_len);
1097   memcpy (n->addr, address, address_len);
1098   n->bandwidth_in = bandwidth_in;
1099   n->bandwidth_out = bandwidth_out;
1100   n->addrlen = address_len;
1101   n->session = session;
1102   GNUNET_free_non_null (n->plugin_name);
1103   n->plugin_name = GNUNET_strdup (plugin_name);
1104   GNUNET_SCHEDULER_cancel (n->timeout_task);
1105   n->timeout_task =
1106       GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1107                                     &neighbour_timeout_task, n);
1108
1109   if (n->state == S_DISCONNECT)
1110   {
1111     /* We are disconnecting, nothing to do here */
1112     return GNUNET_NO;
1113   }
1114   /* We are not connected/connecting and initiate a fresh connect */
1115   if (n->state == S_NOT_CONNECTED)
1116   {
1117     msg_len = sizeof (struct SessionConnectMessage);
1118     connect_msg.header.size = htons (msg_len);
1119     connect_msg.header.type =
1120         htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT);
1121     connect_msg.reserved = htonl (0);
1122     connect_msg.timestamp =
1123         GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
1124
1125     ret = send_with_plugin (peer, (const char *) &connect_msg, msg_len, 0, GNUNET_TIME_UNIT_FOREVER_REL, session, plugin_name, address, address_len, GNUNET_YES, &send_connect_continuation, n);
1126     if (ret == GNUNET_SYSERR)
1127     {
1128       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1129                 "Failed to send CONNECT_MESSAGE to `%4s' using plugin `%s' address '%s' session %X\n",
1130                 GNUNET_i2s (peer), plugin_name,
1131                 (address_len == 0) ? "<inbound>" : GST_plugins_a2s (plugin_name,
1132                                                                     address,
1133                                                                     address_len),
1134                 session);
1135     }
1136     return GNUNET_NO;
1137   }
1138   /* We received a CONNECT message and asked ATS for an address */
1139   else if (n->state == S_CONNECT_RECV)
1140   {
1141     msg_len = sizeof (struct SessionConnectMessage);
1142     connect_msg.header.size = htons (msg_len);
1143     connect_msg.header.type =
1144       htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT_ACK);
1145     connect_msg.reserved = htonl (0);
1146     connect_msg.timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
1147
1148     ret = send_with_plugin(&n->id, (const void *) &connect_msg, msg_len, 0, GNUNET_TIME_UNIT_FOREVER_REL, session, plugin_name, address, address_len, GNUNET_YES, &send_connect_ack_continuation, n);
1149     if (ret == GNUNET_SYSERR)
1150     {
1151       change_state (n, S_NOT_CONNECTED);
1152       GNUNET_break (0);
1153     }
1154     return GNUNET_NO;
1155   }
1156   /* connected peer is switching addresses */
1157   else if (n->state == S_CONNECTED)
1158   {
1159     msg_len = sizeof (struct SessionConnectMessage);
1160     connect_msg.header.size = htons (msg_len);
1161     connect_msg.header.type =
1162         htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT);
1163     connect_msg.reserved = htonl (0);
1164     connect_msg.timestamp =
1165         GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
1166
1167     ret = send_with_plugin (peer, (const char *) &connect_msg, msg_len, 0, GNUNET_TIME_UNIT_FOREVER_REL, session, plugin_name, address, address_len, GNUNET_YES, &send_switch_address_continuation, n);
1168     if (ret == GNUNET_SYSERR)
1169     {
1170       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1171                 "Failed to send CONNECT_MESSAGE to `%4s' using plugin `%s' address '%s' session %X\n",
1172                 GNUNET_i2s (peer), plugin_name,
1173                 (address_len == 0) ? "<inbound>" : GST_plugins_a2s (plugin_name,
1174                                                                     address,
1175                                                                     address_len),
1176                 session);
1177     }
1178     return GNUNET_NO;
1179   }
1180
1181   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid connection state to switch addresses %u ", n->state);
1182   GNUNET_break_op (0);
1183   return GNUNET_NO;
1184 }
1185
1186
1187 /**
1188  * Create an entry in the neighbour map for the given peer
1189  * 
1190  * @param peer peer to create an entry for
1191  * @return new neighbour map entry
1192  */
1193 static struct NeighbourMapEntry *
1194 setup_neighbour (const struct GNUNET_PeerIdentity *peer)
1195 {
1196   struct NeighbourMapEntry *n;
1197
1198 #if DEBUG_TRANSPORT
1199   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1200               "Unknown peer `%s', creating new neighbour\n",
1201               GNUNET_i2s (peer));
1202 #endif
1203   n = GNUNET_malloc (sizeof (struct NeighbourMapEntry));
1204   n->id = *peer;
1205   n->state = S_NOT_CONNECTED;
1206   GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
1207                                  GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
1208                                  MAX_BANDWIDTH_CARRY_S);
1209   n->timeout_task =
1210     GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1211                                   &neighbour_timeout_task, n);
1212   GNUNET_assert (GNUNET_OK ==
1213                  GNUNET_CONTAINER_multihashmap_put (neighbours,
1214                                                     &n->id.hashPubKey, n,
1215                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1216   return n;
1217 }
1218
1219
1220 /**
1221  * Try to create a connection to the given target (eventually).
1222  *
1223  * @param target peer to try to connect to
1224  */
1225 void
1226 GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target)
1227 {
1228   struct NeighbourMapEntry *n;
1229
1230   GNUNET_assert (neighbours != NULL);
1231 #if DEBUG_TRANSPORT
1232   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to connect to peer `%s'\n",
1233               GNUNET_i2s (target));
1234 #endif
1235   GNUNET_assert (0 !=
1236                  memcmp (target, &GST_my_identity,
1237                          sizeof (struct GNUNET_PeerIdentity)));
1238   n = lookup_neighbour (target);
1239
1240   if (NULL != n)
1241   {
1242     if ((is_connected(n)) || (is_connecting(n)))
1243       return;                     /* already connecting or connected */
1244     if (is_disconnecting(n))
1245       change_state (n, S_NOT_CONNECTED);
1246   }
1247
1248
1249   if (n == NULL)
1250     n = setup_neighbour (target);
1251 #if DEBUG_TRANSPORT
1252   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1253               "Asking ATS for suggested address to connect to peer `%s'\n",
1254               GNUNET_i2s (&n->id));
1255 #endif
1256    GNUNET_ATS_suggest_address (GST_ats, &n->id);
1257 }
1258
1259
1260 /**
1261  * Test if we're connected to the given peer.
1262  *
1263  * @param target peer to test
1264  * @return GNUNET_YES if we are connected, GNUNET_NO if not
1265  */
1266 int
1267 GST_neighbours_test_connected (const struct GNUNET_PeerIdentity *target)
1268 {
1269   struct NeighbourMapEntry *n;
1270
1271   GNUNET_assert (neighbours != NULL);
1272
1273   n = lookup_neighbour (target);
1274
1275   if ((NULL == n) || (!is_connected(n)))
1276     return GNUNET_NO;           /* not connected */
1277   return GNUNET_YES;
1278 }
1279
1280
1281 /**
1282  * A session was terminated. Take note.
1283  *
1284  * @param peer identity of the peer where the session died
1285  * @param session session that is gone
1286  */
1287 void
1288 GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer,
1289                                    struct Session *session)
1290 {
1291   struct NeighbourMapEntry *n;
1292
1293   GNUNET_assert (neighbours != NULL);
1294
1295 #if DEBUG_TRANSPORT
1296   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1297               "Session %X to peer `%s' ended \n",
1298               session, GNUNET_i2s (peer));
1299 #endif
1300
1301   n = lookup_neighbour (peer);
1302   if (NULL == n)
1303     return;
1304   if (session != n->session)
1305     return;                     /* doesn't affect us */
1306
1307   n->session = NULL;
1308   GNUNET_free (n->addr);
1309   n->addr = NULL;
1310   n->addrlen = 0;
1311
1312   /* not connected anymore anyway, shouldn't matter */
1313   if ((!is_connected(n)) && (!is_connecting(n)))
1314     return;
1315
1316   // FIXME: switch address what is the state
1317   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Do not forget to fix this!\n");
1318
1319   /* We are connected, so ask ATS to switch addresses */
1320   GNUNET_SCHEDULER_cancel (n->timeout_task);
1321   n->timeout_task =
1322       GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_DISCONNECT_SESSION_TIMEOUT,
1323                                     &neighbour_timeout_task, n);
1324   /* try QUICKLY to re-establish a connection, reduce timeout! */
1325   GNUNET_ATS_suggest_address (GST_ats, peer);
1326 }
1327
1328
1329 /**
1330  * Transmit a message to the given target using the active connection.
1331  *
1332  * @param target destination
1333  * @param msg message to send
1334  * @param msg_size number of bytes in msg
1335  * @param timeout when to fail with timeout
1336  * @param cont function to call when done
1337  * @param cont_cls closure for 'cont'
1338  */
1339 void
1340 GST_neighbours_send (const struct GNUNET_PeerIdentity *target, const void *msg,
1341                      size_t msg_size, struct GNUNET_TIME_Relative timeout,
1342                      GST_NeighbourSendContinuation cont, void *cont_cls)
1343 {
1344   struct NeighbourMapEntry *n;
1345   struct MessageQueue *mq;
1346
1347   GNUNET_assert (neighbours != NULL);
1348
1349   n = lookup_neighbour (target);
1350   if ((n == NULL) || (!is_connected(n)))
1351   {
1352     GNUNET_STATISTICS_update (GST_stats,
1353                               gettext_noop
1354                               ("# messages not sent (no such peer or not connected)"),
1355                               1, GNUNET_NO);
1356 #if DEBUG_TRANSPORT
1357     if (n == NULL)
1358       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1359                   "Could not send message to peer `%s': unknown neighbour",
1360                   GNUNET_i2s (target));
1361     else if (!is_connected(n))
1362       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1363                   "Could not send message to peer `%s': not connected\n",
1364                   GNUNET_i2s (target));
1365 #endif
1366     if (NULL != cont)
1367       cont (cont_cls, GNUNET_SYSERR);
1368     return;
1369   }
1370
1371   if ((n->session == NULL) && (n->addr == NULL) && (n->addrlen ==0))
1372   {
1373     GNUNET_STATISTICS_update (GST_stats,
1374                               gettext_noop
1375                               ("# messages not sent (no such peer or not connected)"),
1376                               1, GNUNET_NO);
1377 #if DEBUG_TRANSPORT
1378       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1379                   "Could not send message to peer `%s': no address available\n",
1380                   GNUNET_i2s (target));
1381 #endif
1382
1383     if (NULL != cont)
1384       cont (cont_cls, GNUNET_SYSERR);
1385     return;
1386   }
1387
1388   GNUNET_assert (msg_size >= sizeof (struct GNUNET_MessageHeader));
1389   GNUNET_STATISTICS_update (GST_stats,
1390                             gettext_noop
1391                             ("# bytes in message queue for other peers"),
1392                             msg_size, GNUNET_NO);
1393   mq = GNUNET_malloc (sizeof (struct MessageQueue) + msg_size);
1394   mq->cont = cont;
1395   mq->cont_cls = cont_cls;
1396   /* FIXME: this memcpy can be up to 7% of our total runtime! */
1397   memcpy (&mq[1], msg, msg_size);
1398   mq->message_buf = (const char *) &mq[1];
1399   mq->message_buf_size = msg_size;
1400   mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1401   GNUNET_CONTAINER_DLL_insert_tail (n->messages_head, n->messages_tail, mq);
1402
1403   if ((GNUNET_SCHEDULER_NO_TASK == n->transmission_task) &&
1404       (NULL == n->is_active))
1405     n->transmission_task = GNUNET_SCHEDULER_add_now (&transmission_task, n);
1406 }
1407
1408
1409 /**
1410  * We have received a message from the given sender.  How long should
1411  * we delay before receiving more?  (Also used to keep the peer marked
1412  * as live).
1413  *
1414  * @param sender sender of the message
1415  * @param size size of the message
1416  * @param do_forward set to GNUNET_YES if the message should be forwarded to clients
1417  *                   GNUNET_NO if the neighbour is not connected or violates the quota,
1418  *                   GNUNET_SYSERR if the connection is not fully up yet
1419  * @return how long to wait before reading more from this sender
1420  */
1421 struct GNUNET_TIME_Relative
1422 GST_neighbours_calculate_receive_delay (const struct GNUNET_PeerIdentity
1423                                         *sender, ssize_t size, int *do_forward)
1424 {
1425   struct NeighbourMapEntry *n;
1426   struct GNUNET_TIME_Relative ret;
1427
1428   GNUNET_assert (neighbours != NULL);
1429
1430   n = lookup_neighbour (sender);
1431   if (n == NULL)
1432   {
1433     GST_neighbours_try_connect (sender);
1434     n = lookup_neighbour (sender);
1435     if (NULL == n)
1436     {
1437       GNUNET_STATISTICS_update (GST_stats,
1438                                 gettext_noop
1439                                 ("# messages discarded due to lack of neighbour record"),
1440                                 1, GNUNET_NO);
1441       *do_forward = GNUNET_NO;
1442       return GNUNET_TIME_UNIT_ZERO;
1443     }
1444   }
1445   if (!is_connected(n))
1446   {
1447     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1448                 _("Plugin gave us %d bytes of data but somehow the session is not marked as UP yet!\n"),
1449                 (int) size);
1450     *do_forward = GNUNET_SYSERR;
1451     return GNUNET_TIME_UNIT_ZERO;
1452   }
1453   if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, size))
1454   {
1455     n->quota_violation_count++;
1456 #if DEBUG_TRANSPORT
1457     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1458                 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
1459                 n->in_tracker.available_bytes_per_s__,
1460                 n->quota_violation_count);
1461 #endif
1462     /* Discount 32k per violation */
1463     GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, -32 * 1024);
1464   }
1465   else
1466   {
1467     if (n->quota_violation_count > 0)
1468     {
1469       /* try to add 32k back */
1470       GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, 32 * 1024);
1471       n->quota_violation_count--;
1472     }
1473   }
1474   if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
1475   {
1476     GNUNET_STATISTICS_update (GST_stats,
1477                               gettext_noop
1478                               ("# bandwidth quota violations by other peers"),
1479                               1, GNUNET_NO);
1480     *do_forward = GNUNET_NO;
1481     return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
1482   }
1483   *do_forward = GNUNET_YES;
1484   ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 32 * 1024);
1485   if (ret.rel_value > 0)
1486   {
1487 #if DEBUG_TRANSPORT
1488     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1489                 "Throttling read (%llu bytes excess at %u b/s), waiting %llu ms before reading more.\n",
1490                 (unsigned long long) n->in_tracker.
1491                 consumption_since_last_update__,
1492                 (unsigned int) n->in_tracker.available_bytes_per_s__,
1493                 (unsigned long long) ret.rel_value);
1494 #endif
1495     GNUNET_STATISTICS_update (GST_stats,
1496                               gettext_noop ("# ms throttling suggested"),
1497                               (int64_t) ret.rel_value, GNUNET_NO);
1498   }
1499   return ret;
1500 }
1501
1502
1503 /**
1504  * Keep the connection to the given neighbour alive longer,
1505  * we received a KEEPALIVE (or equivalent).
1506  *
1507  * @param neighbour neighbour to keep alive
1508  */
1509 void
1510 GST_neighbours_keepalive (const struct GNUNET_PeerIdentity *neighbour)
1511 {
1512   struct NeighbourMapEntry *n;
1513
1514   GNUNET_assert (neighbours != NULL);
1515
1516   n = lookup_neighbour (neighbour);
1517   if (NULL == n)
1518   {
1519     GNUNET_STATISTICS_update (GST_stats,
1520                               gettext_noop
1521                               ("# KEEPALIVE messages discarded (not connected)"),
1522                               1, GNUNET_NO);
1523     return;
1524   }
1525   GNUNET_SCHEDULER_cancel (n->timeout_task);
1526   n->timeout_task =
1527       GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1528                                     &neighbour_timeout_task, n);
1529 }
1530
1531
1532 /**
1533  * Change the incoming quota for the given peer.
1534  *
1535  * @param neighbour identity of peer to change qutoa for
1536  * @param quota new quota
1537  */
1538 void
1539 GST_neighbours_set_incoming_quota (const struct GNUNET_PeerIdentity *neighbour,
1540                                    struct GNUNET_BANDWIDTH_Value32NBO quota)
1541 {
1542   struct NeighbourMapEntry *n;
1543
1544   GNUNET_assert (neighbours != NULL);
1545
1546   n = lookup_neighbour (neighbour);
1547   if (n == NULL)
1548   {
1549     GNUNET_STATISTICS_update (GST_stats,
1550                               gettext_noop
1551                               ("# SET QUOTA messages ignored (no such peer)"),
1552                               1, GNUNET_NO);
1553     return;
1554   }
1555   GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker, quota);
1556   if (0 != ntohl (quota.value__))
1557     return;
1558 #if DEBUG_TRANSPORT
1559   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s' due to `%s'\n",
1560               GNUNET_i2s (&n->id), "SET_QUOTA");
1561 #endif
1562   if (is_connected(n))
1563     GNUNET_STATISTICS_update (GST_stats,
1564                               gettext_noop ("# disconnects due to quota of 0"), 1,
1565                               GNUNET_NO);
1566   disconnect_neighbour (n);
1567 }
1568
1569
1570 /**
1571  * Closure for the neighbours_iterate function.
1572  */
1573 struct IteratorContext
1574 {
1575   /**
1576    * Function to call on each connected neighbour.
1577    */
1578   GST_NeighbourIterator cb;
1579
1580   /**
1581    * Closure for 'cb'.
1582    */
1583   void *cb_cls;
1584 };
1585
1586
1587 /**
1588  * Call the callback from the closure for each connected neighbour.
1589  *
1590  * @param cls the 'struct IteratorContext'
1591  * @param key the hash of the public key of the neighbour
1592  * @param value the 'struct NeighbourMapEntry'
1593  * @return GNUNET_OK (continue to iterate)
1594  */
1595 static int
1596 neighbours_iterate (void *cls, const GNUNET_HashCode * key, void *value)
1597 {
1598   struct IteratorContext *ic = cls;
1599   struct NeighbourMapEntry *n = value;
1600
1601   if (is_connected(n))
1602     return GNUNET_OK;
1603
1604   ic->cb (ic->cb_cls, &n->id, NULL, 0, n->plugin_name, n->addr, n->addrlen);
1605   return GNUNET_OK;
1606 }
1607
1608
1609 /**
1610  * Iterate over all connected neighbours.
1611  *
1612  * @param cb function to call
1613  * @param cb_cls closure for cb
1614  */
1615 void
1616 GST_neighbours_iterate (GST_NeighbourIterator cb, void *cb_cls)
1617 {
1618   struct IteratorContext ic;
1619
1620   GNUNET_assert (neighbours != NULL);
1621
1622   ic.cb = cb;
1623   ic.cb_cls = cb_cls;
1624   GNUNET_CONTAINER_multihashmap_iterate (neighbours, &neighbours_iterate, &ic);
1625 }
1626
1627 /**
1628  * If we have an active connection to the given target, it must be shutdown.
1629  *
1630  * @param target peer to disconnect from
1631  */
1632 void
1633 GST_neighbours_force_disconnect (const struct GNUNET_PeerIdentity *target)
1634 {
1635   struct NeighbourMapEntry *n;
1636
1637   GNUNET_assert (neighbours != NULL);
1638
1639   n = lookup_neighbour (target);
1640   if (NULL == n)
1641     return;                     /* not active */
1642   if (is_connected(n))
1643   {
1644     send_disconnect(n);
1645
1646     n = lookup_neighbour (target);
1647     if (NULL == n)
1648       return;                     /* gone already */
1649   }
1650   disconnect_neighbour (n);
1651 }
1652
1653
1654 /**
1655  * We received a disconnect message from the given peer,
1656  * validate and process.
1657  * 
1658  * @param peer sender of the message
1659  * @param msg the disconnect message
1660  */
1661 void
1662 GST_neighbours_handle_disconnect_message (const struct GNUNET_PeerIdentity *peer,
1663                                           const struct GNUNET_MessageHeader *msg)
1664 {
1665   struct NeighbourMapEntry *n;
1666   const struct SessionDisconnectMessage *sdm;
1667   GNUNET_HashCode hc;
1668
1669 #if DEBUG_TRANSPORT
1670   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1671       "Received DISCONNECT message from peer `%s'\n", GNUNET_i2s (peer));
1672 #endif
1673
1674   if (ntohs (msg->size) != sizeof (struct SessionDisconnectMessage))
1675   {
1676     // GNUNET_break_op (0);
1677     GNUNET_STATISTICS_update (GST_stats,
1678                               gettext_noop ("# disconnect messages ignored (old format)"), 1,
1679                               GNUNET_NO);
1680     return;
1681   }
1682   sdm = (const struct SessionDisconnectMessage* ) msg;
1683   n = lookup_neighbour (peer);
1684   if (NULL == n)
1685     return;                     /* gone already */
1686   if (GNUNET_TIME_absolute_ntoh (sdm->timestamp).abs_value <=
1687       n->connect_ts.abs_value)
1688   {
1689     GNUNET_STATISTICS_update (GST_stats,
1690                               gettext_noop ("# disconnect messages ignored (timestamp)"), 1,
1691                               GNUNET_NO);
1692     return;
1693   }
1694   GNUNET_CRYPTO_hash (&sdm->public_key,
1695                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1696                       &hc);
1697   if (0 != memcmp (peer,
1698                    &hc,
1699                    sizeof (struct GNUNET_PeerIdentity)))
1700   {
1701     GNUNET_break_op (0);
1702     return;
1703   }
1704   if (ntohl (sdm->purpose.size) != 
1705       sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
1706       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) +
1707       sizeof (struct GNUNET_TIME_AbsoluteNBO))
1708   {
1709     GNUNET_break_op (0);
1710     return;
1711   }
1712   if (GNUNET_OK !=
1713       GNUNET_CRYPTO_rsa_verify (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT,
1714                                 &sdm->purpose,
1715                                 &sdm->signature,
1716                                 &sdm->public_key))
1717   {
1718     GNUNET_break_op (0);
1719     return;
1720   }
1721   GST_neighbours_force_disconnect (peer);
1722 }
1723
1724 /**
1725  * We received a 'SESSION_CONNECT_ACK' message from the other peer.
1726  * Consider switching to it.
1727  *
1728  * @param message possibly a 'struct SessionConnectMessage' (check format)
1729  * @param peer identity of the peer to switch the address for
1730  * @param plugin_name name of transport that delivered the PONG
1731  * @param address address of the other peer, NULL if other peer
1732  *                       connected to us
1733  * @param address_len number of bytes in address
1734  * @param session session to use (or NULL)
1735  * @param ats performance data
1736  * @param ats_count number of entries in ats
1737   */
1738 void
1739 GST_neighbours_handle_connect_ack (const struct GNUNET_MessageHeader *message,
1740                                const struct GNUNET_PeerIdentity *peer,
1741                                const char *plugin_name,
1742                                const char *sender_address, uint16_t sender_address_len,
1743                                struct Session *session,
1744                                const struct GNUNET_ATS_Information *ats,
1745                                uint32_t ats_count)
1746 {
1747   const struct SessionConnectMessage *scm;
1748   struct QuotaSetMessage q_msg;
1749   struct GNUNET_MessageHeader msg;
1750   struct GNUNET_TIME_Absolute ts;
1751   struct NeighbourMapEntry *n;
1752   size_t msg_len;
1753   size_t ret;
1754
1755 #if DEBUG_TRANSPORT
1756 #endif
1757   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1758       "Received CONNECT_ACK message from peer `%s'\n", GNUNET_i2s (peer));
1759
1760
1761   if (ntohs (message->size) != sizeof (struct SessionConnectMessage))
1762   {
1763     GNUNET_break_op (0);
1764     return;
1765   }
1766
1767   scm = (const struct SessionConnectMessage *) message;
1768   GNUNET_break_op (ntohl (scm->reserved) == 0);
1769   ts = GNUNET_TIME_absolute_ntoh (scm->timestamp);
1770   n = lookup_neighbour (peer);
1771   if (NULL == n)
1772     n = setup_neighbour (peer);
1773 /*
1774   if (n->state != S_CONNECT_SENT)
1775   {
1776     GNUNET_break (0);
1777     send_disconnect(n);
1778     return;
1779   }
1780 */
1781   if (NULL != session)
1782     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1783                      "transport-ats",
1784                      "Giving ATS session %p of plugin %s for peer %s\n",
1785                      session,
1786                      plugin_name,
1787                      GNUNET_i2s (peer));
1788   GNUNET_ATS_address_update (GST_ats,
1789                              peer,
1790                              plugin_name, sender_address, sender_address_len,
1791                              session, ats, ats_count);
1792
1793   change_state (n, S_CONNECTED);
1794
1795 #if DEBUG_TRANSPORT
1796   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1797               "Setting inbound quota of %u for peer `%s' to \n",
1798               ntohl (n->bandwidth_in.value__), GNUNET_i2s (&n->id));
1799 #endif
1800   GST_neighbours_set_incoming_quota(&n->id, n->bandwidth_in);
1801
1802   n->keepalive_task = GNUNET_SCHEDULER_add_delayed (KEEPALIVE_FREQUENCY,
1803                                                       &neighbour_keepalive_task,
1804                                                       n);
1805   /* send ACK (ACK)*/
1806   msg_len =  sizeof (msg);
1807   msg.size = htons (msg_len);
1808   msg.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK);
1809
1810   ret = send_with_plugin (&n->id, (const char *) &msg, msg_len, 0,
1811       GNUNET_TIME_UNIT_FOREVER_REL,
1812       n->session, n->plugin_name, n->addr, n->addrlen,
1813       GNUNET_YES, NULL, NULL);
1814
1815   if (ret == GNUNET_SYSERR)
1816     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1817               "Failed to send SESSION_ACK to `%4s' using plugin `%s' address '%s' session %X\n",
1818               GNUNET_i2s (&n->id), n->plugin_name,
1819               (n->addrlen == 0) ? "<inbound>" : GST_plugins_a2s (n->plugin_name,
1820                                                                  n->addr,
1821                                                                  n->addrlen),
1822               n->session);
1823
1824   neighbours_connected++;
1825   GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), 1,
1826                             GNUNET_NO);
1827   connect_notify_cb (callback_cls, &n->id, ats, ats_count);
1828
1829 #if DEBUG_TRANSPORT
1830   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1831               "Sending outbound quota of %u Bps for peer `%s' to all clients\n",
1832               ntohl (n->bandwidth_out.value__), GNUNET_i2s (peer));
1833 #endif
1834   q_msg.header.size = htons (sizeof (struct QuotaSetMessage));
1835   q_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA);
1836   q_msg.quota = n->bandwidth_out;
1837   q_msg.peer = (*peer);
1838   GST_clients_broadcast (&q_msg.header, GNUNET_NO);
1839 }
1840
1841 void
1842 GST_neighbours_handle_ack (const struct GNUNET_MessageHeader *message,
1843     const struct GNUNET_PeerIdentity *peer,
1844     const char *plugin_name,
1845     const char *sender_address, uint16_t sender_address_len,
1846     struct Session *session,
1847     const struct GNUNET_ATS_Information *ats,
1848     uint32_t ats_count)
1849 {
1850   struct NeighbourMapEntry *n;
1851   struct QuotaSetMessage q_msg;
1852
1853 #if DEBUG_TRANSPORT
1854   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1855       "Received ACK message from peer `%s'\n", GNUNET_i2s (peer));
1856 #endif
1857
1858   if (ntohs (message->size) != sizeof (struct GNUNET_MessageHeader))
1859   {
1860     GNUNET_break_op (0);
1861     return;
1862   }
1863
1864   n = lookup_neighbour (peer);
1865   if (NULL == n)
1866   {
1867     send_disconnect(n);
1868     GNUNET_break (0);
1869   }
1870 // FIXME check this
1871 //  if (n->state != S_CONNECT_RECV)
1872   if (is_connecting(n))
1873   {
1874     send_disconnect (n);
1875     change_state (n, S_DISCONNECT);
1876     GNUNET_break (0);
1877     return;
1878   }
1879
1880   if (is_connected(n))
1881     return;
1882
1883   if (NULL != session)
1884     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1885                      "transport-ats",
1886                      "Giving ATS session %p of plugin %s for peer %s\n",
1887                      session,
1888                      plugin_name,
1889                      GNUNET_i2s (peer));
1890   GNUNET_ATS_address_update (GST_ats,
1891                              peer,
1892                              plugin_name, sender_address, sender_address_len,
1893                              session, ats, ats_count);
1894
1895   change_state (n, S_CONNECTED);
1896
1897   GST_neighbours_set_incoming_quota(&n->id, n->bandwidth_in);
1898
1899   n->keepalive_task = GNUNET_SCHEDULER_add_delayed (KEEPALIVE_FREQUENCY,
1900                                                       &neighbour_keepalive_task,
1901                                                       n);
1902
1903   neighbours_connected++;
1904   GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), 1,
1905                             GNUNET_NO);
1906   connect_notify_cb (callback_cls, &n->id, ats, ats_count);
1907
1908 #if DEBUG_TRANSPORT
1909   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1910               "Sending outbound quota of %u Bps for peer `%s' to all clients\n",
1911               ntohl (n->bandwidth_out.value__), GNUNET_i2s (peer));
1912 #endif
1913
1914   q_msg.header.size = htons (sizeof (struct QuotaSetMessage));
1915   q_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA);
1916   q_msg.quota = n->bandwidth_out;
1917   q_msg.peer = (*peer);
1918   GST_clients_broadcast (&q_msg.header, GNUNET_NO);
1919 }
1920
1921 struct BlackListCheckContext
1922 {
1923   struct GNUNET_ATS_Information *ats;
1924
1925   uint32_t ats_count;
1926
1927   struct Session *session;
1928
1929   char *sender_address;
1930
1931   uint16_t sender_address_len;
1932
1933   char *plugin_name;
1934
1935   struct GNUNET_TIME_Absolute ts;
1936 };
1937
1938
1939 static void
1940 handle_connect_blacklist_cont (void *cls,
1941                                const struct GNUNET_PeerIdentity
1942                                * peer, int result)
1943 {
1944   struct NeighbourMapEntry *n;
1945   struct BlackListCheckContext * bcc = cls;
1946
1947 #if DEBUG_TRANSPORT
1948   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1949       "Blacklist check due to CONNECT message: `%s'\n", GNUNET_i2s (peer), (result == GNUNET_OK) ? "ALLOWED" : "FORBIDDEN");
1950 #endif
1951
1952   /* not allowed */
1953   if (GNUNET_OK != result)
1954   {
1955     GNUNET_free (bcc);
1956     return;
1957   }
1958
1959   n = lookup_neighbour (peer);
1960   if (NULL == n)
1961     n = setup_neighbour (peer);
1962
1963   if (bcc->ts.abs_value > n->connect_ts.abs_value)
1964   {
1965     if (NULL != bcc->session)
1966       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1967                        "transport-ats",
1968                        "Giving ATS session %p of plugin %s address `%s' for peer %s\n",
1969                        bcc->session,
1970                        bcc->plugin_name,
1971                        GST_plugins_a2s (bcc->plugin_name, bcc->sender_address, bcc->sender_address_len),
1972                        GNUNET_i2s (peer));
1973     GNUNET_ATS_address_update (GST_ats,
1974                                peer,
1975                                bcc->plugin_name, bcc->sender_address, bcc->sender_address_len,
1976                                bcc->session, bcc->ats, bcc->ats_count);
1977     n->connect_ts = bcc->ts;
1978   }
1979
1980   GNUNET_free (bcc);
1981   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1982       "Blacklist check due to CONNECT message: `%s'\n");
1983 /*
1984   if (n->state != S_NOT_CONNECTED)
1985     return;*/
1986   change_state (n, S_CONNECT_RECV);
1987
1988   /* Ask ATS for an address to connect via that address */
1989   GNUNET_ATS_suggest_address(GST_ats, peer);
1990 }
1991
1992 /**
1993  * We received a 'SESSION_CONNECT' message from the other peer.
1994  * Consider switching to it.
1995  *
1996  * @param message possibly a 'struct SessionConnectMessage' (check format)
1997  * @param peer identity of the peer to switch the address for
1998  * @param plugin_name name of transport that delivered the PONG
1999  * @param address address of the other peer, NULL if other peer
2000  *                       connected to us
2001  * @param address_len number of bytes in address
2002  * @param session session to use (or NULL)
2003  * @param ats performance data
2004  * @param ats_count number of entries in ats (excluding 0-termination)
2005   */
2006 void
2007 GST_neighbours_handle_connect (const struct GNUNET_MessageHeader *message,
2008                                const struct GNUNET_PeerIdentity *peer,
2009                                const char *plugin_name,
2010                                const char *sender_address, uint16_t sender_address_len,
2011                                struct Session *session,
2012                                const struct GNUNET_ATS_Information *ats,
2013                                uint32_t ats_count)
2014 {
2015   const struct SessionConnectMessage *scm;
2016   struct NeighbourMapEntry * n;
2017   struct BlackListCheckContext * bcc = NULL;
2018
2019 #if DEBUG_TRANSPORT
2020 #endif
2021   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2022       "Received CONNECT message from peer `%s'\n", GNUNET_i2s (peer));
2023
2024
2025   if (ntohs (message->size) != sizeof (struct SessionConnectMessage))
2026   {
2027     GNUNET_break_op (0);
2028     return;
2029   }
2030
2031   scm = (const struct SessionConnectMessage *) message;
2032   GNUNET_break_op (ntohl (scm->reserved) == 0);
2033
2034   n = lookup_neighbour(peer);
2035   if (n != NULL)
2036   {
2037     /* connected peer switches addresses */
2038     if (is_connected(n))
2039     {
2040       GNUNET_ATS_address_update(GST_ats, peer, plugin_name, sender_address, sender_address_len, session, ats, ats_count);
2041       return;
2042     }
2043   }
2044
2045   /* we are not connected to this peer */
2046   /* do blacklist check*/
2047   bcc = GNUNET_malloc (sizeof (struct BlackListCheckContext) +
2048             sizeof (struct GNUNET_ATS_Information) * ats_count +
2049             sender_address_len +
2050             strlen (plugin_name)+1);
2051
2052   bcc->ts = GNUNET_TIME_absolute_ntoh (scm->timestamp);
2053
2054   bcc->ats_count = ats_count;
2055   bcc->sender_address_len = sender_address_len;
2056   bcc->session = session;
2057
2058   bcc->ats = (struct GNUNET_ATS_Information *) &bcc[1];
2059   memcpy (bcc->ats, ats,sizeof (struct GNUNET_ATS_Information) * ats_count );
2060
2061   bcc->sender_address = (char *) &bcc->ats[ats_count];
2062   memcpy (bcc->sender_address, sender_address , sender_address_len);
2063
2064   bcc->plugin_name = &bcc->sender_address[sender_address_len];
2065   strcpy (bcc->plugin_name, plugin_name);
2066
2067   GST_blacklist_test_allowed (peer, plugin_name, handle_connect_blacklist_cont, bcc);
2068 }
2069
2070
2071 /* end of file gnunet-service-transport_neighbours.c */