initial ATS service refactoring
[oweals/gnunet.git] / src / transport / gnunet-service-transport_neighbours.c
1 /*
2      This file is part of GNUnet.
3      (C) 2010,2011 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file transport/gnunet-service-transport_neighbours.c
23  * @brief neighbour management
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_ats_service.h"
28 #include "gnunet-service-transport_neighbours.h"
29 #include "gnunet-service-transport_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 address suggestion.
130    * NULL after we are connected.
131    */
132   struct GNUNET_ATS_SuggestionContext *asc;
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->asc)
343     {
344       GNUNET_ATS_suggest_address_cancel (n->asc);
345       n->asc = 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 plugin_name name of the plugin
404  * @param plugin_address binary address
405  * @param plugin_address_len length of address
406  * @param ats performance data for the address (as far as known)
407  * @param ats_count number of performance records in 'ats'
408  */
409 static void
410 try_connect_using_address (void *cls,
411                            const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key,
412                            const struct GNUNET_PeerIdentity *target,
413                            const char *plugin_name,
414                            const void *plugin_address,
415                            size_t plugin_address_len,
416                            const struct GNUNET_TRANSPORT_ATS_Information *ats,
417                            uint32_t ats_count)
418 {
419   struct NeighbourMapEntry *n = cls;
420
421   n->asc = NULL;
422   if (n->public_key_valid == GNUNET_NO)
423     {
424       n->public_key = *public_key;
425       n->public_key_valid = GNUNET_YES;
426     }
427   /* FIXME: do connect! */
428
429 }
430
431
432 /**
433  * We've tried to connect but waited long enough and failed.  Clean up.
434  *
435  * @param cls the 'struct NeighbourMapEntry' of the neighbour that failed to connect
436  * @param tc scheduler context
437  */
438 static void
439 neighbour_connect_timeout_task (void *cls,
440                                 const struct GNUNET_SCHEDULER_TaskContext *tc)
441 {
442   struct NeighbourMapEntry *n = cls;
443
444   n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
445   GNUNET_assert (GNUNET_YES ==
446                  GNUNET_CONTAINER_multihashmap_remove (neighbours,
447                                                        &n->id.hashPubKey,
448                                                        n));
449   GNUNET_assert (NULL == n->messages_head);
450   GNUNET_assert (NULL == n->ats);
451   GNUNET_free (n);
452 }
453
454
455 /**
456  * Try to create a connection to the given target (eventually).
457  *
458  * @param target peer to try to connect to
459  */
460 void
461 GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target)
462 {
463   struct NeighbourMapEntry *n;
464
465   GNUNET_assert (0 != memcmp (target,
466                               &GST_my_identity,
467                               sizeof (struct GNUNET_PeerIdentity)));
468   n = lookup_neighbour (target);
469   if ( (NULL != n) ||
470        (GNUNET_TIME_absolute_get_remaining (n->peer_timeout).rel_value > 0) )
471     return; /* already connected */
472   if (n == NULL)
473     {
474       n = GNUNET_malloc (sizeof (struct NeighbourMapEntry));
475       n->id = *target;
476       GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
477                                      GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
478                                      MAX_BANDWIDTH_CARRY_S);
479       n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
480                                                       &neighbour_connect_timeout_task, n);
481       GNUNET_assert (GNUNET_OK ==
482                      GNUNET_CONTAINER_multihashmap_put (neighbours,
483                                                         &n->id.hashPubKey,
484                                                         n,
485                                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
486     }
487   if (n->asc != NULL)
488     return; /* already trying */
489   n->asc = GNUNET_ATS_suggest_address (GST_ats,
490                                        target,
491                                        &try_connect_using_address,
492                                        n); 
493 }
494
495
496 /**
497  * Test if we're connected to the given peer.
498  * 
499  * @param target peer to test
500  * @return GNUNET_YES if we are connected, GNUNET_NO if not
501  */
502 int
503 GST_neighbours_test_connected (const struct GNUNET_PeerIdentity *target)
504 {
505   struct NeighbourMapEntry *n;
506
507   n = lookup_neighbour (target);
508   if ( (NULL == n) ||
509        (GNUNET_TIME_absolute_get_remaining (n->peer_timeout).rel_value == 0) )
510        return GNUNET_NO; /* not connected */
511   return GNUNET_YES;
512 }
513
514
515 /**
516  * Transmit a message to the given target using the active connection.
517  *
518  * @param target destination
519  * @param msg message to send
520  * @param msg_size number of bytes in msg
521  * @param timeout when to fail with timeout
522  * @param cont function to call when done
523  * @param cont_cls closure for 'cont'
524  */
525 void
526 GST_neighbours_send (const struct GNUNET_PeerIdentity *target,
527                      const void *msg,
528                      size_t msg_size,
529                      struct GNUNET_TIME_Relative timeout,
530                      GST_NeighbourSendContinuation cont,
531                      void *cont_cls)
532 {
533   struct NeighbourMapEntry *n;
534   struct MessageQueue *mq;
535
536   n = lookup_neighbour (target);
537   if ( (n == NULL) ||
538        (GNUNET_TIME_absolute_get_remaining (n->peer_timeout).rel_value == 0) ) 
539     {
540       GNUNET_STATISTICS_update (GST_stats,
541                                 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
542                                 1,
543                                 GNUNET_NO);
544       if (NULL != cont)
545         cont (cont_cls,
546               GNUNET_SYSERR);
547       return;
548     }
549   GNUNET_assert (msg_size >= sizeof (struct GNUNET_MessageHeader));
550   GNUNET_STATISTICS_update (GST_stats,
551                             gettext_noop ("# bytes in message queue for other peers"),
552                             msg_size,
553                             GNUNET_NO);
554   mq = GNUNET_malloc (sizeof (struct MessageQueue) + msg_size);
555   /* FIXME: this memcpy can be up to 7% of our total runtime! */
556   memcpy (&mq[1], msg, msg_size);
557   mq->message_buf = (const char*) &mq[1];
558   mq->message_buf_size = msg_size;
559   mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
560   GNUNET_CONTAINER_DLL_insert_tail (n->messages_head,
561                                     n->messages_tail,
562                                     mq);
563   // try_transmission_to_peer (n);
564 }
565
566
567 /**
568  * Change the incoming quota for the given peer.
569  *
570  * @param neighbour identity of peer to change qutoa for
571  * @param quota new quota 
572  */
573 void
574 GST_neighbours_set_incoming_quota (const struct GNUNET_PeerIdentity *neighbour,
575                                    struct GNUNET_BANDWIDTH_Value32NBO quota)
576 {
577   struct NeighbourMapEntry *n;
578
579   n = lookup_neighbour (neighbour);
580   if (n == NULL)
581     {
582       GNUNET_STATISTICS_update (GST_stats,
583                                 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
584                                 1,
585                                 GNUNET_NO);
586       return;
587     }
588   GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
589                                          quota);
590   if (0 != ntohl (quota.value__))
591     return;
592 #if DEBUG_TRANSPORT
593   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
594               "Disconnecting peer `%4s' due to `%s'\n",
595               GNUNET_i2s(&n->id),
596               "SET_QUOTA");
597 #endif
598   GNUNET_STATISTICS_update (GST_stats,
599                             gettext_noop ("# disconnects due to quota of 0"),
600                             1,
601                             GNUNET_NO);
602   disconnect_neighbour (n);
603 }
604
605
606 /**
607  * Closure for the neighbours_iterate function.
608  */
609 struct IteratorContext
610 {
611   /**
612    * Function to call on each connected neighbour.
613    */
614   GST_NeighbourIterator cb;
615
616   /**
617    * Closure for 'cb'.
618    */
619   void *cb_cls;
620 };
621
622
623 /**
624  * Call the callback from the closure for each connected neighbour.
625  *
626  * @param cls the 'struct IteratorContext'
627  * @param key the hash of the public key of the neighbour
628  * @param value the 'struct NeighbourMapEntry'
629  * @return GNUNET_OK (continue to iterate)
630  */
631 static int
632 neighbours_iterate (void *cls,
633                     const GNUNET_HashCode *key,
634                     void *value)
635 {
636   struct IteratorContext *ic = cls;
637   struct NeighbourMapEntry *n = value;
638
639   if (GNUNET_TIME_absolute_get_remaining (n->peer_timeout).rel_value == 0)
640     return GNUNET_OK; /* not connected */
641   GNUNET_assert (n->ats_count > 0);
642   ic->cb (ic->cb_cls,
643           &n->id,
644           n->ats,
645           n->ats_count - 1);
646   return GNUNET_OK;
647 }
648
649
650 /**
651  * Iterate over all connected neighbours.
652  *
653  * @param cb function to call 
654  * @param cb_cls closure for cb
655  */
656 void
657 GST_neighbours_iterate (GST_NeighbourIterator cb,
658                         void *cb_cls)
659 {
660   struct IteratorContext ic;
661
662   ic.cb = cb;
663   ic.cb_cls = cb_cls;
664   GNUNET_CONTAINER_multihashmap_iterate (neighbours,
665                                          &neighbours_iterate,
666                                          &ic);
667 }
668
669
670 /**
671  * Peer has been idle for too long. Disconnect.
672  *
673  * @param cls the 'struct NeighbourMapEntry' of the neighbour that went idle
674  * @param tc scheduler context
675  */
676 static void
677 neighbour_idle_timeout_task (void *cls,
678                              const struct GNUNET_SCHEDULER_TaskContext *tc)
679 {
680   struct NeighbourMapEntry *n = cls;
681
682   n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
683   disconnect_neighbour (n);
684 }
685
686
687 /**
688  * We have received a CONNECT.  Set the peer to connected.
689  *
690  * @param sender peer sending the PONG
691  * @param hdr the PONG message (presumably)
692  * @param plugin_name name of transport that delivered the PONG
693  * @param sender_address address of the other peer, NULL if other peer
694  *                       connected to us
695  * @param sender_address_len number of bytes in sender_address
696  * @param ats performance data
697  * @param ats_count number of entries in ats (excluding 0-termination)
698  * @return GNUNET_OK if the message was well-formed, GNUNET_SYSERR if not
699  */
700 int
701 GST_neighbours_handle_connect (const struct GNUNET_PeerIdentity *sender,
702                                const struct GNUNET_MessageHeader *hdr,
703                                const char *plugin_name,
704                                const void *sender_address,
705                                size_t sender_address_len,
706                                struct Session *session,
707                                const struct GNUNET_TRANSPORT_ATS_Information *ats,
708                                uint32_t ats_count)
709 {  
710   struct NeighbourMapEntry *n;
711
712   if (0 == memcmp (sender,
713                    &GST_my_identity,
714                    sizeof (struct GNUNET_PeerIdentity)))
715     {
716       GNUNET_break (0);
717       return GNUNET_SYSERR;
718     } 
719   n = lookup_neighbour (sender);
720   if ( (NULL != n) ||
721        (n->is_connected == GNUNET_YES) )
722     {
723       /* already connected */
724       if (session != NULL)
725         {
726           // FIXME: ATS: switch session!?
727           // FIXME: merge/update ats?
728         }
729       return GNUNET_OK; 
730     }
731   if (n == NULL)
732     {
733       n = GNUNET_malloc (sizeof (struct NeighbourMapEntry));
734       n->id = *sender;
735       GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
736                                      GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
737                                      MAX_BANDWIDTH_CARRY_S);
738       n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
739                                                       &neighbour_connect_timeout_task, n);
740       GNUNET_assert (GNUNET_OK ==
741                      GNUNET_CONTAINER_multihashmap_put (neighbours,
742                                                         &n->id.hashPubKey,
743                                                         n,
744                                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
745       if (NULL == ats)
746         {
747           GNUNET_array_grow (n->ats,
748                              n->ats_count,
749                              1);
750         }
751       else
752         {
753           GNUNET_array_grow (n->ats,
754                              n->ats_count,
755                              ats_count);
756           memcpy (n->ats,
757                   ats, 
758                   sizeof (struct GNUNET_TRANSPORT_ATS_Information) * ats_count);
759         }
760     }
761   if (session != NULL)
762     {
763       // FIXME: ATS: switch session!?
764       // n->session = session;
765     }
766   n->peer_timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
767   if (GNUNET_SCHEDULER_NO_TASK != n->timeout_task)
768     GNUNET_SCHEDULER_cancel (n->timeout_task);
769   n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
770                                                   &neighbour_idle_timeout_task,
771                                                   n);
772   n->is_connected = GNUNET_YES;  
773   connect_notify_cb (callback_cls,
774                      sender,
775                      n->ats,
776                      n->ats_count);
777   return GNUNET_OK;
778 }
779
780
781 /**
782  * If we have an active connection to the given target, it must be shutdown.
783  *
784  * @param target peer to disconnect from
785  */
786 void
787 GST_neighbours_force_disconnect (const struct GNUNET_PeerIdentity *target)
788 {
789   struct NeighbourMapEntry *n;
790
791   n = lookup_neighbour (target);
792   /* FIXME: send disconnect message to target... */
793   disconnect_neighbour (n);
794 }
795
796
797 /**
798  * We have received a DISCONNECT.  Set the peer to disconnected.
799  *
800  * @param sender peer sending the PONG
801  * @param hdr the PONG message (presumably)
802  * @param plugin_name name of transport that delivered the PONG
803  * @param sender_address address of the other peer, NULL if other peer
804  *                       connected to us
805  * @param sender_address_len number of bytes in sender_address
806  * @return GNUNET_OK if the message was well-formed, GNUNET_SYSERR if not
807  */
808 int
809 GST_neighbours_handle_disconnect (const struct GNUNET_PeerIdentity *sender,
810                                   const struct GNUNET_MessageHeader *hdr,
811                                   const char *plugin_name,
812                                   const void *sender_address,
813                                   size_t sender_address_len)
814 {
815   struct NeighbourMapEntry *n;
816
817   n = lookup_neighbour (sender);
818   /* FIXME: should disconnects have a signature that we should check here? */
819   disconnect_neighbour (n);
820   return GNUNET_OK;
821 }
822
823
824 /* end of file gnunet-service-transport_neighbours.c */