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