stuff
[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-service-transport_neighbours.h"
28 #include "gnunet-service-transport_validation.h"
29 #include "gnunet-service-transport.h"
30 #include "gnunet_peerinfo_service.h"
31 #include "gnunet_constants.h"
32 #include "transport.h"
33
34
35 /**
36  * Size of the neighbour hash map.
37  */
38 #define NEIGHBOUR_TABLE_SIZE 256
39
40
41
42 // TODO:
43 // - have a way to access the currently 'connected' session
44 //   (for sending and to notice disconnect of it!)
45 // - have a way to access/update bandwidth/quota information per peer
46 //   (for CostReport/TrafficReport callbacks)
47
48
49 struct NeighbourMapEntry;
50
51 /**
52  * For each neighbour we keep a list of messages
53  * that we still want to transmit to the neighbour.
54  */
55 struct MessageQueue
56 {
57
58   /**
59    * This is a doubly linked list.
60    */
61   struct MessageQueue *next;
62
63   /**
64    * This is a doubly linked list.
65    */
66   struct MessageQueue *prev;
67
68   /**
69    * The message(s) we want to transmit, GNUNET_MessageHeader(s)
70    * stuck together in memory.  Allocated at the end of this struct.
71    */
72   const char *message_buf;
73
74   /**
75    * Size of the message buf
76    */
77   size_t message_buf_size;
78
79   /**
80    * Client responsible for queueing the message; used to check that a
81    * client has no two messages pending for the same target and to
82    * notify the client of a successful transmission; NULL if this is
83    * an internal message.
84    */
85   struct TransportClient *client;
86
87   /**
88    * At what time should we fail?
89    */
90   struct GNUNET_TIME_Absolute timeout;
91
92   /**
93    * Internal message of the transport system that should not be
94    * included in the usual SEND-SEND_OK transmission confirmation
95    * traffic management scheme.  Typically, "internal_msg" will
96    * be set whenever "client" is NULL (but it is not strictly
97    * required).
98    */
99   int internal_msg;
100
101   /**
102    * How important is the message?
103    */
104   unsigned int priority;
105
106 };
107
108
109 /**
110  * Entry in neighbours. 
111  */
112 struct NeighbourMapEntry
113 {
114
115   /**
116    * Head of list of messages we would like to send to this peer;
117    * must contain at most one message per client.
118    */
119   struct MessageQueue *messages_head;
120
121   /**
122    * Tail of list of messages we would like to send to this peer; must
123    * contain at most one message per client.
124    */
125   struct MessageQueue *messages_tail;
126
127   /**
128    * Context for validation address iteration.
129    * NULL after we are connected.
130    */
131   struct GST_ValidationIteratorContext *vic;
132
133   /**
134    * Performance data for the peer.
135    */
136   struct GNUNET_TRANSPORT_ATS_Information *ats;
137
138   /**
139    * Public key for this peer.  Valid only if the respective flag is set below.
140    */
141   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
142
143   /**
144    * Identity of this neighbour.
145    */
146   struct GNUNET_PeerIdentity id;
147
148   /**
149    * ID of task scheduled to run when this peer is about to
150    * time out (will free resources associated with the peer).
151    */
152   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
153
154   /**
155    * ID of task scheduled to run when we should retry transmitting
156    * the head of the message queue.  Actually triggered when the
157    * transmission is timing out (we trigger instantly when we have
158    * a chance of success).
159    */
160   GNUNET_SCHEDULER_TaskIdentifier retry_task;
161
162   /**
163    * How long until we should consider this peer dead (if we don't
164    * receive another message in the meantime)?
165    */
166   struct GNUNET_TIME_Absolute peer_timeout;
167
168   /**
169    * Tracker for inbound bandwidth.
170    */
171   struct GNUNET_BANDWIDTH_Tracker in_tracker;
172
173   /**
174    * The latency we have seen for this particular address for
175    * this particular peer.  This latency may have been calculated
176    * over multiple transports.  This value reflects how long it took
177    * us to receive a response when SENDING via this particular
178    * transport/neighbour/address combination!
179    *
180    * FIXME: we need to periodically send PINGs to update this
181    * latency (at least more often than the current "huge" (11h?)
182    * update interval).
183    */
184   struct GNUNET_TIME_Relative latency;
185
186   /**
187    * How often has the other peer (recently) violated the inbound
188    * traffic limit?  Incremented by 10 per violation, decremented by 1
189    * per non-violation (for each time interval).
190    */
191   unsigned int quota_violation_count;
192
193   /**
194    * DV distance to this peer (1 if no DV is used).
195    */
196   uint32_t distance;
197   
198   /**
199    * Number of values in 'ats' array.
200    */
201   unsigned int ats_count;
202
203   /**
204    * Have we seen an PONG from this neighbour in the past (and
205    * not had a disconnect since)?
206    */
207   int received_pong;
208
209   /**
210    * Do we have a valid public key for this neighbour?
211    */
212   int public_key_valid;
213
214   /**
215    * Are we already in the process of disconnecting this neighbour?
216    */
217   int in_disconnect;
218
219   /**
220    * Do we currently consider this neighbour connected? (as far as
221    * the connect/disconnect callbacks are concerned)?
222    */
223   int is_connected;
224
225 };
226
227
228 /**
229  * All known neighbours and their HELLOs.
230  */
231 static struct GNUNET_CONTAINER_MultiHashMap *neighbours;
232
233 /**
234  * Closure for connect_notify_cb and disconnect_notify_cb
235  */
236 static void *callback_cls;
237
238 /**
239  * Function to call when we connected to a neighbour.
240  */
241 static GNUNET_TRANSPORT_NotifyConnect connect_notify_cb;
242
243 /**
244  * Function to call when we disconnected from a neighbour.
245  */
246 static GNUNET_TRANSPORT_NotifyDisconnect disconnect_notify_cb;
247
248
249 /**
250  * Lookup a neighbour entry in the neighbours hash map.
251  *
252  * @param pid identity of the peer to look up
253  * @return the entry, NULL if there is no existing record
254  */
255 static struct NeighbourMapEntry *
256 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
257 {
258   return GNUNET_CONTAINER_multihashmap_get (neighbours,
259                                             &pid->hashPubKey);
260 }
261
262
263 #if 0
264 /**
265  * Check the ready list for the given neighbour and if a plugin is
266  * ready for transmission (and if we have a message), do so!
267  *
268  * @param neighbour target peer for which to transmit
269  */
270 static void
271 try_transmission_to_peer (struct NeighbourMapEntry *n)
272 {
273   struct MessageQueue *mq;
274   struct GNUNET_TIME_Relative timeout;
275   ssize_t ret;
276
277   if (n->messages_head == NULL)
278     {
279 #if DEBUG_TRANSPORT
280       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
281                   "Transmission queue for `%4s' is empty\n",
282                   GNUNET_i2s (&n->id));
283 #endif
284       return;                     /* nothing to do */
285     }
286   mq = n->messages_head;
287   GNUNET_CONTAINER_DLL_remove (n->messages_head,
288                                n->messages_tail,
289                                mq);
290   ret = papi->send (papi->cls,
291                     &n->pid,
292                     mq->message_buf,
293                     mq->message_buf_size,
294                     mq->priority,
295                     GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
296                     n->session,
297                     n->addr,
298                     n->addrlen,
299                     GNUNET_YES /*?*/,
300                     &transmit_send_continuation, mq);
301   if (ret == -1)
302     {
303       /* failure, but 'send' would not call continuation in this case,
304          so we need to do it here! */
305       transmit_send_continuation (mq,
306                                   &mq->neighbour_id,
307                                   GNUNET_SYSERR);
308     }
309 }
310 #endif
311
312
313 /**
314  * Initialize the neighbours subsystem.
315  *
316  * @param cls closure for callbacks
317  * @param connect_cb function to call if we connect to a peer
318  * @param disconnect_cb function to call if we disconnect from a peer
319  */
320 void 
321 GST_neighbours_start (void *cls,
322                       GNUNET_TRANSPORT_NotifyConnect connect_cb,
323                       GNUNET_TRANSPORT_NotifyDisconnect disconnect_cb)
324 {
325   callback_cls = cls;
326   connect_notify_cb = connect_cb;
327   disconnect_notify_cb = disconnect_cb;
328   neighbours = GNUNET_CONTAINER_multihashmap_create (NEIGHBOUR_TABLE_SIZE);
329 }
330
331
332 /**
333  * Disconnect from the given neighbour, clean up the record.
334  *
335  * @param n neighbour to disconnect from
336  */
337 static void
338 disconnect_neighbour (struct NeighbourMapEntry *n)
339 {
340   struct MessageQueue *mq;
341
342   disconnect_notify_cb (callback_cls,
343                         &n->id);
344   GNUNET_assert (GNUNET_YES ==
345                  GNUNET_CONTAINER_multihashmap_remove (neighbours,
346                                                        &n->id.hashPubKey,
347                                                        n));
348   while (NULL != (mq = n->messages_head))
349     {
350       GNUNET_CONTAINER_DLL_remove (n->messages_head,
351                                    n->messages_tail,
352                                    mq);
353       GNUNET_free (mq);
354     }
355   if (NULL != n->vic)
356     {
357       GST_validation_get_addresses_cancel (n->vic);
358       n->vic = NULL;
359     }
360   GNUNET_array_grow (n->ats,
361                      n->ats_count,
362                      0);
363   GNUNET_free (n);
364 }
365
366
367 /**
368  * Disconnect from the given neighbour.
369  *
370  * @param cls unused
371  * @param key hash of neighbour's public key (not used)
372  * @param value the 'struct NeighbourMapEntry' of the neighbour
373  */
374 static int
375 disconnect_all_neighbours (void *cls,
376                            const GNUNET_HashCode *key,
377                            void *value)
378 {
379   struct NeighbourMapEntry *n = value;
380
381 #if DEBUG_TRANSPORT
382   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
383               "Disconnecting peer `%4s', %s\n",
384               GNUNET_i2s(&n->id),
385               "SHUTDOWN_TASK");
386 #endif
387   disconnect_neighbour (n);
388   return GNUNET_OK;
389 }
390
391
392 /**
393  * Cleanup the neighbours subsystem.
394  */
395 void
396 GST_neighbours_stop ()
397 {
398   GNUNET_CONTAINER_multihashmap_iterate (neighbours,
399                                          &disconnect_all_neighbours,
400                                          NULL);
401   GNUNET_CONTAINER_multihashmap_destroy (neighbours);
402   neighbours = NULL;
403   callback_cls = NULL;
404   connect_notify_cb = NULL;
405   disconnect_notify_cb = NULL;
406 }
407
408
409 /**
410  * Try to connect to the target peer using the given address
411  * (if is valid).
412  *
413  * @param cls the 'struct NeighbourMapEntry' of the target
414  * @param public_key public key for the peer, never NULL
415  * @param target identity of the target peer
416  * @param valid_until is ZERO if we never validated the address,
417  *                    otherwise a time up to when we consider it (or was) valid
418  * @param validation_block  is FOREVER if the address is for an unsupported plugin (from PEERINFO)
419  *                          is ZERO if the address is considered valid (no validation needed)
420  *                          otherwise a time in the future if we're currently denying re-validation
421  * @param plugin_name name of the plugin
422  * @param plugin_address binary address
423  * @param plugin_address_len length of address
424  */
425 static void
426 try_connect_using_address (void *cls,
427                            const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key,
428                            const struct GNUNET_PeerIdentity *target,
429                            struct GNUNET_TIME_Absolute valid_until,
430                            struct GNUNET_TIME_Absolute validation_block,
431                            const char *plugin_name,
432                            const void *plugin_address,
433                            size_t plugin_address_len)
434 {
435   struct NeighbourMapEntry *n = cls;
436
437   if (n->public_key_valid == GNUNET_NO)
438     {
439       n->public_key = *public_key;
440       n->public_key_valid = GNUNET_YES;
441     }
442   if (GNUNET_TIME_absolute_get_remaining (valid_until).rel_value == 0)
443     return; /* address is not valid right now */
444   /* FIXME: do ATS here! */
445
446 }
447
448
449 /**
450  * We've tried to connect but waited long enough and failed.  Clean up.
451  *
452  * @param cls the 'struct NeighbourMapEntry' of the neighbour that failed to connect
453  * @param tc scheduler context
454  */
455 static void
456 neighbour_connect_timeout_task (void *cls,
457                                 const struct GNUNET_SCHEDULER_TaskContext *tc)
458 {
459   struct NeighbourMapEntry *n = cls;
460
461   n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
462   GNUNET_assert (GNUNET_YES ==
463                  GNUNET_CONTAINER_multihashmap_remove (neighbours,
464                                                        &n->id.hashPubKey,
465                                                        n));
466   GNUNET_assert (NULL == n->messages_head);
467   GNUNET_assert (NULL == n->ats);
468   GNUNET_free (n);
469 }
470
471
472 /**
473  * Try to create a connection to the given target (eventually).
474  *
475  * @param target peer to try to connect to
476  */
477 void
478 GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target)
479 {
480   struct NeighbourMapEntry *n;
481
482   GNUNET_assert (0 != memcmp (target,
483                               &GST_my_identity,
484                               sizeof (struct GNUNET_PeerIdentity)));
485   n = lookup_neighbour (target);
486   if ( (NULL != n) ||
487        (GNUNET_TIME_absolute_get_remaining (n->peer_timeout).rel_value > 0) )
488     return; /* already connected */
489   if (n == NULL)
490     {
491       n = GNUNET_malloc (sizeof (struct NeighbourMapEntry));
492       n->id = *target;
493       GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
494                                      GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
495                                      MAX_BANDWIDTH_CARRY_S);
496       n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
497       n->distance = UINT32_MAX;
498       n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
499                                                       &neighbour_connect_timeout_task, n);
500       GNUNET_assert (GNUNET_OK ==
501                      GNUNET_CONTAINER_multihashmap_put (neighbours,
502                                                         &n->id.hashPubKey,
503                                                         n,
504                                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
505     }
506   if (n->vic != NULL)
507     return; /* already trying */
508   n->vic = GST_validation_get_addresses (target,
509                                          GNUNET_NO,
510                                          &try_connect_using_address,
511                                          n); 
512 }
513
514
515 /**
516  * Test if we're connected to the given peer.
517  * 
518  * @param target peer to test
519  * @return GNUNET_YES if we are connected, GNUNET_NO if not
520  */
521 int
522 GST_neighbours_test_connected (const struct GNUNET_PeerIdentity *target)
523 {
524   struct NeighbourMapEntry *n;
525
526   n = lookup_neighbour (target);
527   if ( (NULL == n) ||
528        (GNUNET_TIME_absolute_get_remaining (n->peer_timeout).rel_value == 0) )
529        return GNUNET_NO; /* not connected */
530   return GNUNET_YES;
531 }
532
533
534 /**
535  * Transmit a message to the given target using the active connection.
536  *
537  * @param target destination
538  * @param msg message to send
539  * @param timeout when to fail with timeout
540  * @param cont function to call when done
541  * @param cont_cls closure for 'cont'
542  */
543 void
544 GST_neighbours_send (const struct GNUNET_PeerIdentity *target,
545                      const struct GNUNET_MessageHeader *msg,
546                      struct GNUNET_TIME_Relative timeout,
547                      GST_NeighbourSendContinuation cont,
548                      void *cont_cls)
549 {
550   struct NeighbourMapEntry *n;
551   struct MessageQueue *mq;
552   uint16_t message_buf_size;
553
554   n = lookup_neighbour (target);
555   if ( (n == NULL) ||
556        (GNUNET_TIME_absolute_get_remaining (n->peer_timeout).rel_value == 0) ) 
557     {
558       GNUNET_STATISTICS_update (GST_stats,
559                                 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
560                                 1,
561                                 GNUNET_NO);
562       if (NULL != cont)
563         cont (cont_cls,
564               GNUNET_SYSERR);
565       return;
566     }
567   message_buf_size = ntohs (msg->size);
568   GNUNET_assert (message_buf_size >= sizeof (struct GNUNET_MessageHeader));
569   GNUNET_STATISTICS_update (GST_stats,
570                             gettext_noop ("# bytes in message queue for other peers"),
571                             message_buf_size,
572                             GNUNET_NO);
573   mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
574   /* FIXME: this memcpy can be up to 7% of our total runtime! */
575   memcpy (&mq[1], msg, message_buf_size);
576   mq->message_buf = (const char*) &mq[1];
577   mq->message_buf_size = message_buf_size;
578   mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
579   GNUNET_CONTAINER_DLL_insert_tail (n->messages_head,
580                                     n->messages_tail,
581                                     mq);
582   // try_transmission_to_peer (n);
583 }
584
585
586 /**
587  * Change the incoming quota for the given peer.
588  *
589  * @param neighbour identity of peer to change qutoa for
590  * @param quota new quota 
591  */
592 void
593 GST_neighbours_set_incoming_quota (const struct GNUNET_PeerIdentity *neighbour,
594                                    struct GNUNET_BANDWIDTH_Value32NBO quota)
595 {
596   struct NeighbourMapEntry *n;
597
598   n = lookup_neighbour (neighbour);
599   if (n == NULL)
600     {
601       GNUNET_STATISTICS_update (GST_stats,
602                                 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
603                                 1,
604                                 GNUNET_NO);
605       return;
606     }
607   GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
608                                          quota);
609   if (0 != ntohl (quota.value__))
610     return;
611 #if DEBUG_TRANSPORT
612   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
613               "Disconnecting peer `%4s' due to `%s'\n",
614               GNUNET_i2s(&n->id),
615               "SET_QUOTA");
616 #endif
617   GNUNET_STATISTICS_update (GST_stats,
618                             gettext_noop ("# disconnects due to quota of 0"),
619                             1,
620                             GNUNET_NO);
621   disconnect_neighbour (n);
622 }
623
624
625 /**
626  * Closure for the neighbours_iterate function.
627  */
628 struct IteratorContext
629 {
630   /**
631    * Function to call on each connected neighbour.
632    */
633   GST_NeighbourIterator cb;
634
635   /**
636    * Closure for 'cb'.
637    */
638   void *cb_cls;
639 };
640
641
642 /**
643  * Call the callback from the closure for each connected neighbour.
644  *
645  * @param cls the 'struct IteratorContext'
646  * @param key the hash of the public key of the neighbour
647  * @param value the 'struct NeighbourMapEntry'
648  * @return GNUNET_OK (continue to iterate)
649  */
650 static int
651 neighbours_iterate (void *cls,
652                     const GNUNET_HashCode *key,
653                     void *value)
654 {
655   struct IteratorContext *ic = cls;
656   struct NeighbourMapEntry *n = value;
657
658   if (GNUNET_TIME_absolute_get_remaining (n->peer_timeout).rel_value == 0)
659     return GNUNET_OK; /* not connected */
660   GNUNET_assert (n->ats_count > 0);
661   ic->cb (ic->cb_cls,
662           &n->id,
663           n->ats,
664           n->ats_count - 1);
665   return GNUNET_OK;
666 }
667
668
669 /**
670  * Iterate over all connected neighbours.
671  *
672  * @param cb function to call 
673  * @param cb_cls closure for cb
674  */
675 void
676 GST_neighbours_iterate (GST_NeighbourIterator cb,
677                         void *cb_cls)
678 {
679   struct IteratorContext ic;
680
681   ic.cb = cb;
682   ic.cb_cls = cb_cls;
683   GNUNET_CONTAINER_multihashmap_iterate (neighbours,
684                                          &neighbours_iterate,
685                                          &ic);
686 }
687
688
689 /**
690  * We have received a CONNECT.  Set the peer to connected.
691  *
692  * @param sender peer sending the PONG
693  * @param hdr the PONG message (presumably)
694  * @param plugin_name name of transport that delivered the PONG
695  * @param sender_address address of the other peer, NULL if other peer
696  *                       connected to us
697  * @param sender_address_len number of bytes in sender_address
698  * @param ats performance data
699  * @param ats_count number of entries in ats (excluding 0-termination)
700  * @return GNUNET_OK if the message was well-formed, GNUNET_SYSERR if not
701  */
702 int
703 GST_neighbours_handle_connect (const struct GNUNET_PeerIdentity *sender,
704                                const struct GNUNET_MessageHeader *hdr,
705                                const char *plugin_name,
706                                const void *sender_address,
707                                size_t sender_address_len,
708                                struct Session *session,
709                                const struct GNUNET_TRANSPORT_ATS_Information *ats,
710                                uint32_t ats_count)
711 {  
712   struct NeighbourMapEntry *n;
713
714   if (0 == memcmp (sender,
715                    &GST_my_identity,
716                    sizeof (struct GNUNET_PeerIdentity)))
717     {
718       GNUNET_break (0);
719       return GNUNET_SYSERR;
720     }
721   n = lookup_neighbour (sender);
722   if ( (NULL != n) ||
723        (n->is_connected == GNUNET_YES) )
724     {
725       /* already connected */
726       if (session != NULL)
727         {
728           // FIXME: ATS: switch session!?
729           // FIXME: merge/update ats?
730         }
731       return GNUNET_OK; 
732     }
733   if (n == NULL)
734     {
735       n = GNUNET_malloc (sizeof (struct NeighbourMapEntry));
736       n->id = *sender;
737       GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
738                                      GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
739                                      MAX_BANDWIDTH_CARRY_S);
740       n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
741       n->distance = UINT32_MAX;
742       n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
743                                                       &neighbour_connect_timeout_task, n);
744       GNUNET_assert (GNUNET_OK ==
745                      GNUNET_CONTAINER_multihashmap_put (neighbours,
746                                                         &n->id.hashPubKey,
747                                                         n,
748                                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
749       if (NULL == ats)
750         {
751           GNUNET_array_grow (n->ats,
752                              n->ats_count,
753                              1);
754         }
755       else
756         {
757           GNUNET_array_grow (n->ats,
758                              n->ats_count,
759                              ats_count);
760           memcpy (n->ats,
761                   ats, 
762                   sizeof (struct GNUNET_TRANSPORT_ATS_Information) * ats_count);
763         }
764     }
765   if (session != NULL)
766     {
767       // FIXME: ATS: switch session!?
768       // n->session = session;
769     }
770   n->is_connected = GNUNET_YES;
771   connect_notify_cb (callback_cls,
772                      sender,
773                      n->ats,
774                      n->ats_count);
775   return GNUNET_OK;
776 }
777
778
779 /**
780  * If we have an active connection to the given target, it must be shutdown.
781  *
782  * @param target peer to disconnect from
783  */
784 void
785 GST_neighbours_force_disconnect (const struct GNUNET_PeerIdentity *target)
786 {
787   struct NeighbourMapEntry *n;
788
789   n = lookup_neighbour (target);
790   /* FIXME: send disconnect message to target... */
791   disconnect_neighbour (n);
792 }
793
794
795 /**
796  * We have received a DISCONNECT.  Set the peer to disconnected.
797  *
798  * @param sender peer sending the PONG
799  * @param hdr the PONG message (presumably)
800  * @param plugin_name name of transport that delivered the PONG
801  * @param sender_address address of the other peer, NULL if other peer
802  *                       connected to us
803  * @param sender_address_len number of bytes in sender_address
804  * @return GNUNET_OK if the message was well-formed, GNUNET_SYSERR if not
805  */
806 int
807 GST_neighbours_handle_disconnect (const struct GNUNET_PeerIdentity *sender,
808                                   const struct GNUNET_MessageHeader *hdr,
809                                   const char *plugin_name,
810                                   const void *sender_address,
811                                   size_t sender_address_len)
812 {
813   struct NeighbourMapEntry *n;
814
815   n = lookup_neighbour (sender);
816   /* FIXME: should disconnects have a signature that we should check here? */
817   disconnect_neighbour (n);
818   return GNUNET_OK;
819 }
820
821
822 /* end of file gnunet-service-transport_neighbours.c */