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    * How often has the other peer (recently) violated the inbound
175    * traffic limit?  Incremented by 10 per violation, decremented by 1
176    * per non-violation (for each time interval).
177    */
178   unsigned int quota_violation_count;
179
180   /**
181    * Number of values in 'ats' array.
182    */
183   unsigned int ats_count;
184
185   /**
186    * Have we seen an PONG from this neighbour in the past (and
187    * not had a disconnect since)?
188    */
189   int received_pong;
190
191   /**
192    * Do we have a valid public key for this neighbour?
193    */
194   int public_key_valid;
195
196   /**
197    * Are we already in the process of disconnecting this neighbour?
198    */
199   int in_disconnect;
200
201   /**
202    * Do we currently consider this neighbour connected? (as far as
203    * the connect/disconnect callbacks are concerned)?
204    */
205   int is_connected;
206
207 };
208
209
210 /**
211  * All known neighbours and their HELLOs.
212  */
213 static struct GNUNET_CONTAINER_MultiHashMap *neighbours;
214
215 /**
216  * Closure for connect_notify_cb and disconnect_notify_cb
217  */
218 static void *callback_cls;
219
220 /**
221  * Function to call when we connected to a neighbour.
222  */
223 static GNUNET_TRANSPORT_NotifyConnect connect_notify_cb;
224
225 /**
226  * Function to call when we disconnected from a neighbour.
227  */
228 static GNUNET_TRANSPORT_NotifyDisconnect disconnect_notify_cb;
229
230
231 /**
232  * Lookup a neighbour entry in the neighbours hash map.
233  *
234  * @param pid identity of the peer to look up
235  * @return the entry, NULL if there is no existing record
236  */
237 static struct NeighbourMapEntry *
238 lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
239 {
240   return GNUNET_CONTAINER_multihashmap_get (neighbours,
241                                             &pid->hashPubKey);
242 }
243
244
245 #if 0
246 /**
247  * Check the ready list for the given neighbour and if a plugin is
248  * ready for transmission (and if we have a message), do so!
249  *
250  * @param neighbour target peer for which to transmit
251  */
252 static void
253 try_transmission_to_peer (struct NeighbourMapEntry *n)
254 {
255   struct MessageQueue *mq;
256   struct GNUNET_TIME_Relative timeout;
257   ssize_t ret;
258
259   if (n->messages_head == NULL)
260     {
261 #if DEBUG_TRANSPORT
262       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
263                   "Transmission queue for `%4s' is empty\n",
264                   GNUNET_i2s (&n->id));
265 #endif
266       return;                     /* nothing to do */
267     }
268   mq = n->messages_head;
269   GNUNET_CONTAINER_DLL_remove (n->messages_head,
270                                n->messages_tail,
271                                mq);
272   ret = papi->send (papi->cls,
273                     &n->pid,
274                     mq->message_buf,
275                     mq->message_buf_size,
276                     mq->priority,
277                     GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
278                     n->session,
279                     n->addr,
280                     n->addrlen,
281                     GNUNET_YES /*?*/,
282                     &transmit_send_continuation, mq);
283   if (ret == -1)
284     {
285       /* failure, but 'send' would not call continuation in this case,
286          so we need to do it here! */
287       transmit_send_continuation (mq,
288                                   &mq->neighbour_id,
289                                   GNUNET_SYSERR);
290     }
291 }
292 #endif
293
294
295 /**
296  * Initialize the neighbours subsystem.
297  *
298  * @param cls closure for callbacks
299  * @param connect_cb function to call if we connect to a peer
300  * @param disconnect_cb function to call if we disconnect from a peer
301  */
302 void 
303 GST_neighbours_start (void *cls,
304                       GNUNET_TRANSPORT_NotifyConnect connect_cb,
305                       GNUNET_TRANSPORT_NotifyDisconnect disconnect_cb)
306 {
307   callback_cls = cls;
308   connect_notify_cb = connect_cb;
309   disconnect_notify_cb = disconnect_cb;
310   neighbours = GNUNET_CONTAINER_multihashmap_create (NEIGHBOUR_TABLE_SIZE);
311 }
312
313
314 /**
315  * Disconnect from the given neighbour, clean up the record.
316  *
317  * @param n neighbour to disconnect from
318  */
319 static void
320 disconnect_neighbour (struct NeighbourMapEntry *n)
321 {
322   struct MessageQueue *mq;
323
324   if (n->is_connected)
325     {
326       disconnect_notify_cb (callback_cls,
327                             &n->id);
328       n->is_connected = GNUNET_NO;
329     }
330   GNUNET_assert (GNUNET_YES ==
331                  GNUNET_CONTAINER_multihashmap_remove (neighbours,
332                                                        &n->id.hashPubKey,
333                                                        n));
334   while (NULL != (mq = n->messages_head))
335     {
336       GNUNET_CONTAINER_DLL_remove (n->messages_head,
337                                    n->messages_tail,
338                                    mq);
339       GNUNET_free (mq);
340     }
341   if (NULL != n->vic)
342     {
343       GST_validation_get_addresses_cancel (n->vic);
344       n->vic = NULL;
345     }
346   GNUNET_array_grow (n->ats,
347                      n->ats_count,
348                      0);
349   GNUNET_free (n);
350 }
351
352
353 /**
354  * Disconnect from the given neighbour.
355  *
356  * @param cls unused
357  * @param key hash of neighbour's public key (not used)
358  * @param value the 'struct NeighbourMapEntry' of the neighbour
359  */
360 static int
361 disconnect_all_neighbours (void *cls,
362                            const GNUNET_HashCode *key,
363                            void *value)
364 {
365   struct NeighbourMapEntry *n = value;
366
367 #if DEBUG_TRANSPORT
368   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
369               "Disconnecting peer `%4s', %s\n",
370               GNUNET_i2s(&n->id),
371               "SHUTDOWN_TASK");
372 #endif
373   disconnect_neighbour (n);
374   return GNUNET_OK;
375 }
376
377
378 /**
379  * Cleanup the neighbours subsystem.
380  */
381 void
382 GST_neighbours_stop ()
383 {
384   GNUNET_CONTAINER_multihashmap_iterate (neighbours,
385                                          &disconnect_all_neighbours,
386                                          NULL);
387   GNUNET_CONTAINER_multihashmap_destroy (neighbours);
388   neighbours = NULL;
389   callback_cls = NULL;
390   connect_notify_cb = NULL;
391   disconnect_notify_cb = NULL;
392 }
393
394
395 /**
396  * Try to connect to the target peer using the given address
397  * (if is valid).
398  *
399  * @param cls the 'struct NeighbourMapEntry' of the target
400  * @param public_key public key for the peer, never NULL
401  * @param target identity of the target peer
402  * @param valid_until is ZERO if we never validated the address,
403  *                    otherwise a time up to when we consider it (or was) valid
404  * @param validation_block  is FOREVER if the address is for an unsupported plugin (from PEERINFO)
405  *                          is ZERO if the address is considered valid (no validation needed)
406  *                          otherwise a time in the future if we're currently denying re-validation
407  * @param plugin_name name of the plugin
408  * @param plugin_address binary address
409  * @param plugin_address_len length of address
410  */
411 static void
412 try_connect_using_address (void *cls,
413                            const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key,
414                            const struct GNUNET_PeerIdentity *target,
415                            struct GNUNET_TIME_Absolute valid_until,
416                            struct GNUNET_TIME_Absolute validation_block,
417                            const char *plugin_name,
418                            const void *plugin_address,
419                            size_t plugin_address_len)
420 {
421   struct NeighbourMapEntry *n = cls;
422
423   if (n->public_key_valid == GNUNET_NO)
424     {
425       n->public_key = *public_key;
426       n->public_key_valid = GNUNET_YES;
427     }
428   if (GNUNET_TIME_absolute_get_remaining (valid_until).rel_value == 0)
429     return; /* address is not valid right now */
430   /* FIXME: do ATS here! */
431
432 }
433
434
435 /**
436  * We've tried to connect but waited long enough and failed.  Clean up.
437  *
438  * @param cls the 'struct NeighbourMapEntry' of the neighbour that failed to connect
439  * @param tc scheduler context
440  */
441 static void
442 neighbour_connect_timeout_task (void *cls,
443                                 const struct GNUNET_SCHEDULER_TaskContext *tc)
444 {
445   struct NeighbourMapEntry *n = cls;
446
447   n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
448   GNUNET_assert (GNUNET_YES ==
449                  GNUNET_CONTAINER_multihashmap_remove (neighbours,
450                                                        &n->id.hashPubKey,
451                                                        n));
452   GNUNET_assert (NULL == n->messages_head);
453   GNUNET_assert (NULL == n->ats);
454   GNUNET_free (n);
455 }
456
457
458 /**
459  * Try to create a connection to the given target (eventually).
460  *
461  * @param target peer to try to connect to
462  */
463 void
464 GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target)
465 {
466   struct NeighbourMapEntry *n;
467
468   GNUNET_assert (0 != memcmp (target,
469                               &GST_my_identity,
470                               sizeof (struct GNUNET_PeerIdentity)));
471   n = lookup_neighbour (target);
472   if ( (NULL != n) ||
473        (GNUNET_TIME_absolute_get_remaining (n->peer_timeout).rel_value > 0) )
474     return; /* already connected */
475   if (n == NULL)
476     {
477       n = GNUNET_malloc (sizeof (struct NeighbourMapEntry));
478       n->id = *target;
479       GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
480                                      GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
481                                      MAX_BANDWIDTH_CARRY_S);
482       n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
483                                                       &neighbour_connect_timeout_task, n);
484       GNUNET_assert (GNUNET_OK ==
485                      GNUNET_CONTAINER_multihashmap_put (neighbours,
486                                                         &n->id.hashPubKey,
487                                                         n,
488                                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
489     }
490   if (n->vic != NULL)
491     return; /* already trying */
492   n->vic = GST_validation_get_addresses (target,
493                                          GNUNET_NO,
494                                          &try_connect_using_address,
495                                          n); 
496 }
497
498
499 /**
500  * Test if we're connected to the given peer.
501  * 
502  * @param target peer to test
503  * @return GNUNET_YES if we are connected, GNUNET_NO if not
504  */
505 int
506 GST_neighbours_test_connected (const struct GNUNET_PeerIdentity *target)
507 {
508   struct NeighbourMapEntry *n;
509
510   n = lookup_neighbour (target);
511   if ( (NULL == n) ||
512        (GNUNET_TIME_absolute_get_remaining (n->peer_timeout).rel_value == 0) )
513        return GNUNET_NO; /* not connected */
514   return GNUNET_YES;
515 }
516
517
518 /**
519  * Transmit a message to the given target using the active connection.
520  *
521  * @param target destination
522  * @param msg message to send
523  * @param timeout when to fail with timeout
524  * @param cont function to call when done
525  * @param cont_cls closure for 'cont'
526  */
527 void
528 GST_neighbours_send (const struct GNUNET_PeerIdentity *target,
529                      const struct GNUNET_MessageHeader *msg,
530                      struct GNUNET_TIME_Relative timeout,
531                      GST_NeighbourSendContinuation cont,
532                      void *cont_cls)
533 {
534   struct NeighbourMapEntry *n;
535   struct MessageQueue *mq;
536   uint16_t message_buf_size;
537
538   n = lookup_neighbour (target);
539   if ( (n == NULL) ||
540        (GNUNET_TIME_absolute_get_remaining (n->peer_timeout).rel_value == 0) ) 
541     {
542       GNUNET_STATISTICS_update (GST_stats,
543                                 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
544                                 1,
545                                 GNUNET_NO);
546       if (NULL != cont)
547         cont (cont_cls,
548               GNUNET_SYSERR);
549       return;
550     }
551   message_buf_size = ntohs (msg->size);
552   GNUNET_assert (message_buf_size >= sizeof (struct GNUNET_MessageHeader));
553   GNUNET_STATISTICS_update (GST_stats,
554                             gettext_noop ("# bytes in message queue for other peers"),
555                             message_buf_size,
556                             GNUNET_NO);
557   mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
558   /* FIXME: this memcpy can be up to 7% of our total runtime! */
559   memcpy (&mq[1], msg, message_buf_size);
560   mq->message_buf = (const char*) &mq[1];
561   mq->message_buf_size = message_buf_size;
562   mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
563   GNUNET_CONTAINER_DLL_insert_tail (n->messages_head,
564                                     n->messages_tail,
565                                     mq);
566   // try_transmission_to_peer (n);
567 }
568
569
570 /**
571  * Change the incoming quota for the given peer.
572  *
573  * @param neighbour identity of peer to change qutoa for
574  * @param quota new quota 
575  */
576 void
577 GST_neighbours_set_incoming_quota (const struct GNUNET_PeerIdentity *neighbour,
578                                    struct GNUNET_BANDWIDTH_Value32NBO quota)
579 {
580   struct NeighbourMapEntry *n;
581
582   n = lookup_neighbour (neighbour);
583   if (n == NULL)
584     {
585       GNUNET_STATISTICS_update (GST_stats,
586                                 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
587                                 1,
588                                 GNUNET_NO);
589       return;
590     }
591   GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
592                                          quota);
593   if (0 != ntohl (quota.value__))
594     return;
595 #if DEBUG_TRANSPORT
596   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
597               "Disconnecting peer `%4s' due to `%s'\n",
598               GNUNET_i2s(&n->id),
599               "SET_QUOTA");
600 #endif
601   GNUNET_STATISTICS_update (GST_stats,
602                             gettext_noop ("# disconnects due to quota of 0"),
603                             1,
604                             GNUNET_NO);
605   disconnect_neighbour (n);
606 }
607
608
609 /**
610  * Closure for the neighbours_iterate function.
611  */
612 struct IteratorContext
613 {
614   /**
615    * Function to call on each connected neighbour.
616    */
617   GST_NeighbourIterator cb;
618
619   /**
620    * Closure for 'cb'.
621    */
622   void *cb_cls;
623 };
624
625
626 /**
627  * Call the callback from the closure for each connected neighbour.
628  *
629  * @param cls the 'struct IteratorContext'
630  * @param key the hash of the public key of the neighbour
631  * @param value the 'struct NeighbourMapEntry'
632  * @return GNUNET_OK (continue to iterate)
633  */
634 static int
635 neighbours_iterate (void *cls,
636                     const GNUNET_HashCode *key,
637                     void *value)
638 {
639   struct IteratorContext *ic = cls;
640   struct NeighbourMapEntry *n = value;
641
642   if (GNUNET_TIME_absolute_get_remaining (n->peer_timeout).rel_value == 0)
643     return GNUNET_OK; /* not connected */
644   GNUNET_assert (n->ats_count > 0);
645   ic->cb (ic->cb_cls,
646           &n->id,
647           n->ats,
648           n->ats_count - 1);
649   return GNUNET_OK;
650 }
651
652
653 /**
654  * Iterate over all connected neighbours.
655  *
656  * @param cb function to call 
657  * @param cb_cls closure for cb
658  */
659 void
660 GST_neighbours_iterate (GST_NeighbourIterator cb,
661                         void *cb_cls)
662 {
663   struct IteratorContext ic;
664
665   ic.cb = cb;
666   ic.cb_cls = cb_cls;
667   GNUNET_CONTAINER_multihashmap_iterate (neighbours,
668                                          &neighbours_iterate,
669                                          &ic);
670 }
671
672
673 /**
674  * Peer has been idle for too long. Disconnect.
675  *
676  * @param cls the 'struct NeighbourMapEntry' of the neighbour that went idle
677  * @param tc scheduler context
678  */
679 static void
680 neighbour_idle_timeout_task (void *cls,
681                              const struct GNUNET_SCHEDULER_TaskContext *tc)
682 {
683   struct NeighbourMapEntry *n = cls;
684
685   n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
686   disconnect_neighbour (n);
687 }
688
689
690 /**
691  * We have received a CONNECT.  Set the peer to connected.
692  *
693  * @param sender peer sending the PONG
694  * @param hdr the PONG message (presumably)
695  * @param plugin_name name of transport that delivered the PONG
696  * @param sender_address address of the other peer, NULL if other peer
697  *                       connected to us
698  * @param sender_address_len number of bytes in sender_address
699  * @param ats performance data
700  * @param ats_count number of entries in ats (excluding 0-termination)
701  * @return GNUNET_OK if the message was well-formed, GNUNET_SYSERR if not
702  */
703 int
704 GST_neighbours_handle_connect (const struct GNUNET_PeerIdentity *sender,
705                                const struct GNUNET_MessageHeader *hdr,
706                                const char *plugin_name,
707                                const void *sender_address,
708                                size_t sender_address_len,
709                                struct Session *session,
710                                const struct GNUNET_TRANSPORT_ATS_Information *ats,
711                                uint32_t ats_count)
712 {  
713   struct NeighbourMapEntry *n;
714
715   if (0 == memcmp (sender,
716                    &GST_my_identity,
717                    sizeof (struct GNUNET_PeerIdentity)))
718     {
719       GNUNET_break (0);
720       return GNUNET_SYSERR;
721     } 
722   n = lookup_neighbour (sender);
723   if ( (NULL != n) ||
724        (n->is_connected == GNUNET_YES) )
725     {
726       /* already connected */
727       if (session != NULL)
728         {
729           // FIXME: ATS: switch session!?
730           // FIXME: merge/update ats?
731         }
732       return GNUNET_OK; 
733     }
734   if (n == NULL)
735     {
736       n = GNUNET_malloc (sizeof (struct NeighbourMapEntry));
737       n->id = *sender;
738       GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
739                                      GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
740                                      MAX_BANDWIDTH_CARRY_S);
741       n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
742                                                       &neighbour_connect_timeout_task, n);
743       GNUNET_assert (GNUNET_OK ==
744                      GNUNET_CONTAINER_multihashmap_put (neighbours,
745                                                         &n->id.hashPubKey,
746                                                         n,
747                                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
748       if (NULL == ats)
749         {
750           GNUNET_array_grow (n->ats,
751                              n->ats_count,
752                              1);
753         }
754       else
755         {
756           GNUNET_array_grow (n->ats,
757                              n->ats_count,
758                              ats_count);
759           memcpy (n->ats,
760                   ats, 
761                   sizeof (struct GNUNET_TRANSPORT_ATS_Information) * ats_count);
762         }
763     }
764   if (session != NULL)
765     {
766       // FIXME: ATS: switch session!?
767       // n->session = session;
768     }
769   n->peer_timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
770   if (GNUNET_SCHEDULER_NO_TASK != n->timeout_task)
771     GNUNET_SCHEDULER_cancel (n->timeout_task);
772   n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
773                                                   &neighbour_idle_timeout_task,
774                                                   n);
775   n->is_connected = GNUNET_YES;  
776   connect_notify_cb (callback_cls,
777                      sender,
778                      n->ats,
779                      n->ats_count);
780   return GNUNET_OK;
781 }
782
783
784 /**
785  * If we have an active connection to the given target, it must be shutdown.
786  *
787  * @param target peer to disconnect from
788  */
789 void
790 GST_neighbours_force_disconnect (const struct GNUNET_PeerIdentity *target)
791 {
792   struct NeighbourMapEntry *n;
793
794   n = lookup_neighbour (target);
795   /* FIXME: send disconnect message to target... */
796   disconnect_neighbour (n);
797 }
798
799
800 /**
801  * We have received a DISCONNECT.  Set the peer to disconnected.
802  *
803  * @param sender peer sending the PONG
804  * @param hdr the PONG message (presumably)
805  * @param plugin_name name of transport that delivered the PONG
806  * @param sender_address address of the other peer, NULL if other peer
807  *                       connected to us
808  * @param sender_address_len number of bytes in sender_address
809  * @return GNUNET_OK if the message was well-formed, GNUNET_SYSERR if not
810  */
811 int
812 GST_neighbours_handle_disconnect (const struct GNUNET_PeerIdentity *sender,
813                                   const struct GNUNET_MessageHeader *hdr,
814                                   const char *plugin_name,
815                                   const void *sender_address,
816                                   size_t sender_address_len)
817 {
818   struct NeighbourMapEntry *n;
819
820   n = lookup_neighbour (sender);
821   /* FIXME: should disconnects have a signature that we should check here? */
822   disconnect_neighbour (n);
823   return GNUNET_OK;
824 }
825
826
827 /* end of file gnunet-service-transport_neighbours.c */