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