more neighbours code
[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  * Create a fresh entry in our neighbour list for the given peer.
401  * Will try to transmit our current HELLO to the new neighbour.
402  * Do not call this function directly, use 'setup_peer_check_blacklist.
403  *
404  * @param peer the peer for which we create the entry
405  * @param do_hello should we schedule transmitting a HELLO
406  * @return the new neighbour list entry
407  */
408 static struct NeighbourMapEntry *
409 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
410                      int do_hello)
411 {
412   struct NeighbourMapEntry *n;
413   struct TransportPlugin *tp;
414   struct ReadyList *rl;
415
416   GNUNET_assert (0 != memcmp (peer,
417                               &my_identity,
418                               sizeof (struct GNUNET_PeerIdentity)));
419 #if DEBUG_TRANSPORT
420   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
421               "Setting up state for neighbour `%4s'\n",
422               GNUNET_i2s (peer));
423 #endif
424   GNUNET_STATISTICS_update (stats,
425                             gettext_noop ("# active neighbours"),
426                             1,
427                             GNUNET_NO);
428   n = GNUNET_malloc (sizeof (struct NeighbourMapEntry));
429   n->id = *peer;
430   n->peer_timeout =
431     GNUNET_TIME_relative_to_absolute
432     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
433   GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
434                                  GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
435                                  MAX_BANDWIDTH_CARRY_S);
436   tp = plugins;
437   while (tp != NULL)
438     {
439       if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
440         {
441           rl = GNUNET_malloc (sizeof (struct ReadyList));
442           rl->neighbour = n;
443           rl->next = n->plugins;
444           n->plugins = rl;
445           rl->plugin = tp;
446           rl->addresses = NULL;
447         }
448       tp = tp->next;
449     }
450   n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
451   n->distance = -1;
452   n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
453                                                   &neighbour_timeout_task, n);
454   GNUNET_CONTAINER_multihashmap_put (neighbours,
455                                      &n->id.hashPubKey,
456                                      n,
457                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
458   if (do_hello)
459     {
460       GNUNET_STATISTICS_update (stats,
461                                 gettext_noop ("# peerinfo new neighbor iterate requests"),
462                                 1,
463                                 GNUNET_NO);
464       GNUNET_STATISTICS_update (stats,
465                                 gettext_noop ("# outstanding peerinfo iterate requests"),
466                                 1,
467                                 GNUNET_NO);
468       n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
469                                           GNUNET_TIME_UNIT_FOREVER_REL,
470                                           &add_hello_for_peer, n);
471
472       GNUNET_STATISTICS_update (stats,
473                                 gettext_noop ("# HELLO's sent to new neighbors"),
474                                 1,
475                                 GNUNET_NO);
476       if (NULL != our_hello)
477         transmit_to_peer (NULL, NULL, 0,
478                           HELLO_ADDRESS_EXPIRATION,
479                           (const char *) our_hello, GNUNET_HELLO_size(our_hello),
480                           GNUNET_NO, n);
481     }
482   return n;
483 }
484 #endif
485
486
487 /**
488  * Initialize the neighbours subsystem.
489  *
490  * @param cls closure for callbacks
491  * @param connect_cb function to call if we connect to a peer
492  * @param disconnect_cb function to call if we disconnect from a peer
493  */
494 void 
495 GST_neighbours_start (void *cls,
496                       GNUNET_TRANSPORT_NotifyConnect connect_cb,
497                       GNUNET_TRANSPORT_NotifyDisconnect disconnect_cb)
498 {
499   callback_cls = cls;
500   connect_notify_cb = connect_cb;
501   disconnect_notify_cb = disconnect_cb;
502   neighbours = GNUNET_CONTAINER_multihashmap_create (NEIGHBOUR_TABLE_SIZE);
503 }
504
505
506 /**
507  * Disconnect from the given neighbour, clean up the record.
508  *
509  * @param n neighbour to disconnect from
510  */
511 static void
512 disconnect_neighbour (struct NeighbourMapEntry *n)
513 {
514   struct MessageQueue *mq;
515
516   disconnect_notify_cb (callback_cls,
517                         &n->id);
518   GNUNET_assert (GNUNET_YES ==
519                  GNUNET_CONTAINER_multihashmap_remove (neighbours,
520                                                        &n->id.hashPubKey,
521                                                        n));
522   while (NULL != (mq = n->messages_head))
523     {
524       GNUNET_CONTAINER_DLL_remove (n->messages_head,
525                                    n->messages_tail,
526                                    mq);
527       GNUNET_free (mq);
528     }
529   if (NULL != n->piter)
530     {
531       GNUNET_PEERINFO_iterate_cancel (n->piter);
532       n->piter = NULL;
533     }
534   GNUNET_array_grow (n->ats,
535                      n->ats_count,
536                      0);
537   GNUNET_free (n);
538 }
539
540
541 /**
542  * Disconnect from the given neighbour.
543  *
544  * @param cls unused
545  * @param key hash of neighbour's public key (not used)
546  * @param value the 'struct NeighbourMapEntry' of the neighbour
547  */
548 static int
549 disconnect_all_neighbours (void *cls,
550                            const GNUNET_HashCode *key,
551                            void *value)
552 {
553   struct NeighbourMapEntry *n = value;
554
555 #if DEBUG_TRANSPORT
556   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
557               "Disconnecting peer `%4s', %s\n",
558               GNUNET_i2s(&n->id),
559               "SHUTDOWN_TASK");
560 #endif
561   disconnect_neighbour (n);
562   return GNUNET_OK;
563 }
564
565
566 /**
567  * Cleanup the neighbours subsystem.
568  */
569 void
570 GST_neighbours_stop ()
571 {
572   GNUNET_CONTAINER_multihashmap_iterate (neighbours,
573                                          &disconnect_all_neighbours,
574                                          NULL);
575   GNUNET_CONTAINER_multihashmap_destroy (neighbours);
576   neighbours = NULL;
577   callback_cls = NULL;
578   connect_notify_cb = NULL;
579   disconnect_notify_cb = NULL;
580 }
581
582
583 /**
584  * Try to create a connection to the given target (eventually).
585  *
586  * @param target peer to try to connect to
587  */
588 void
589 GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target)
590 {
591 }
592
593
594 /**
595  * Test if we're connected to the given peer.
596  * 
597  * @param target peer to test
598  * @return GNUNET_YES if we are connected, GNUNET_NO if not
599  */
600 int
601 GST_neighbours_test_connected (const struct GNUNET_PeerIdentity *target)
602 {
603   struct NeighbourMapEntry *n;
604
605   n = lookup_neighbour (target);
606   if ( (NULL == n) ||
607        (GNUNET_TIME_absolute_get_remaining (n->peer_timeout).rel_value == 0) )
608        return GNUNET_NO; /* not connected */
609   return GNUNET_YES;
610 }
611
612
613 /**
614  * Transmit a message to the given target using the active connection.
615  *
616  * @param target destination
617  * @param msg message to send
618  * @param timeout when to fail with timeout
619  * @param cont function to call when done
620  * @param cont_cls closure for 'cont'
621  */
622 void
623 GST_neighbours_send (const struct GNUNET_PeerIdentity *target,
624                      const struct GNUNET_MessageHeader *msg,
625                      struct GNUNET_TIME_Relative timeout,
626                      GST_NeighbourSendContinuation cont,
627                      void *cont_cls)
628 {
629   struct NeighbourMapEntry *n;
630   struct MessageQueue *mq;
631   uint16_t message_buf_size;
632
633   n = lookup_neighbour (target);
634   if ( (n == NULL) ||
635        (GNUNET_TIME_absolute_get_remaining (n->peer_timeout).rel_value == 0) ) 
636     {
637       GNUNET_STATISTICS_update (GST_stats,
638                                 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
639                                 1,
640                                 GNUNET_NO);
641       if (NULL != cont)
642         cont (cont_cls,
643               GNUNET_SYSERR);
644       return;
645     }
646   message_buf_size = ntohs (msg->size);
647   GNUNET_assert (message_buf_size >= sizeof (struct GNUNET_MessageHeader));
648   GNUNET_STATISTICS_update (GST_stats,
649                             gettext_noop ("# bytes in message queue for other peers"),
650                             message_buf_size,
651                             GNUNET_NO);
652   mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
653   /* FIXME: this memcpy can be up to 7% of our total runtime! */
654   memcpy (&mq[1], msg, message_buf_size);
655   mq->message_buf = (const char*) &mq[1];
656   mq->message_buf_size = message_buf_size;
657   mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
658   GNUNET_CONTAINER_DLL_insert_tail (n->messages_head,
659                                     n->messages_tail,
660                                     mq);
661   // try_transmission_to_peer (n);
662 }
663
664
665 /**
666  * Change the incoming quota for the given peer.
667  *
668  * @param neighbour identity of peer to change qutoa for
669  * @param quota new quota 
670  */
671 void
672 GST_neighbours_set_incoming_quota (const struct GNUNET_PeerIdentity *neighbour,
673                                    struct GNUNET_BANDWIDTH_Value32NBO quota)
674 {
675   struct NeighbourMapEntry *n;
676
677   n = lookup_neighbour (neighbour);
678   if (n == NULL)
679     {
680       GNUNET_STATISTICS_update (GST_stats,
681                                 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
682                                 1,
683                                 GNUNET_NO);
684       return;
685     }
686   GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
687                                          quota);
688   if (0 != ntohl (quota.value__))
689     return;
690 #if DEBUG_TRANSPORT
691   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
692               "Disconnecting peer `%4s' due to `%s'\n",
693               GNUNET_i2s(&n->id),
694               "SET_QUOTA");
695 #endif
696   GNUNET_STATISTICS_update (GST_stats,
697                             gettext_noop ("# disconnects due to quota of 0"),
698                             1,
699                             GNUNET_NO);
700   disconnect_neighbour (n);
701 }
702
703
704 /**
705  * If we have an active connection to the given target, it must be shutdown.
706  *
707  * @param target peer to disconnect from
708  */
709 void
710 GST_neighbours_force_disconnect (const struct GNUNET_PeerIdentity *target)
711 {
712   struct NeighbourMapEntry *n;
713
714   n = lookup_neighbour (target);
715   disconnect_neighbour (n);
716 }
717
718
719 /**
720  * Closure for the neighbours_iterate function.
721  */
722 struct IteratorContext
723 {
724   /**
725    * Function to call on each connected neighbour.
726    */
727   GST_NeighbourIterator cb;
728
729   /**
730    * Closure for 'cb'.
731    */
732   void *cb_cls;
733 };
734
735
736 /**
737  * Call the callback from the closure for each connected neighbour.
738  *
739  * @param cls the 'struct IteratorContext'
740  * @param key the hash of the public key of the neighbour
741  * @param value the 'struct NeighbourMapEntry'
742  * @return GNUNET_OK (continue to iterate)
743  */
744 static int
745 neighbours_iterate (void *cls,
746                     const GNUNET_HashCode *key,
747                     void *value)
748 {
749   struct IteratorContext *ic = cls;
750   struct NeighbourMapEntry *n = value;
751
752   if (GNUNET_TIME_absolute_get_remaining (n->peer_timeout).rel_value == 0)
753     return GNUNET_OK; /* not connected */
754   GNUNET_assert (n->ats_count > 0);
755   ic->cb (ic->cb_cls,
756           &n->id,
757           n->ats,
758           n->ats_count - 1);
759   return GNUNET_OK;
760 }
761
762
763 /**
764  * Iterate over all connected neighbours.
765  *
766  * @param cb function to call 
767  * @param cb_cls closure for cb
768  */
769 void
770 GST_neighbours_iterate (GST_NeighbourIterator cb,
771                         void *cb_cls)
772 {
773   struct IteratorContext ic;
774
775   ic.cb = cb;
776   ic.cb_cls = cb_cls;
777   GNUNET_CONTAINER_multihashmap_iterate (neighbours,
778                                          &neighbours_iterate,
779                                          &ic);
780 }
781
782
783 /**
784  * We have received a PONG.  Update lifeness of the neighbour.
785  *
786  * @param sender peer sending the PONG
787  * @param hdr the PONG message (presumably)
788  * @param plugin_name name of transport that delivered the PONG
789  * @param sender_address address of the other peer, NULL if other peer
790  *                       connected to us
791  * @param sender_address_len number of bytes in sender_address
792  * @param ats performance data
793  * @param ats_count number of entries in ats (excluding 0-termination)
794  * @return GNUNET_OK if the message was well-formed, GNUNET_SYSERR if not
795  */
796 int
797 GST_neighbours_handle_pong (const struct GNUNET_PeerIdentity *sender,
798                             const struct GNUNET_MessageHeader *hdr,
799                             const char *plugin_name,
800                             const void *sender_address,
801                             size_t sender_address_len,
802                             const struct GNUNET_TRANSPORT_ATS_Information *ats,
803                             uint32_t ats_count)
804 {
805   return GNUNET_SYSERR;
806 }
807
808
809 /**
810  * We have received a CONNECT.  Set the peer to connected.
811  *
812  * @param sender peer sending the PONG
813  * @param hdr the PONG message (presumably)
814  * @param plugin_name name of transport that delivered the PONG
815  * @param sender_address address of the other peer, NULL if other peer
816  *                       connected to us
817  * @param sender_address_len number of bytes in sender_address
818  * @param ats performance data
819  * @param ats_count number of entries in ats (excluding 0-termination)
820  * @return GNUNET_OK if the message was well-formed, GNUNET_SYSERR if not
821  */
822 int
823 GST_neighbours_handle_connect (const struct GNUNET_PeerIdentity *sender,
824                                const struct GNUNET_MessageHeader *hdr,
825                                const char *plugin_name,
826                                const void *sender_address,
827                                size_t sender_address_len,
828                                const struct GNUNET_TRANSPORT_ATS_Information *ats,
829                                uint32_t ats_count)
830 {
831   return GNUNET_SYSERR;
832 }
833
834
835 /**
836  * We have received a DISCONNECT.  Set the peer to disconnected.
837  *
838  * @param sender peer sending the PONG
839  * @param hdr the PONG message (presumably)
840  * @param plugin_name name of transport that delivered the PONG
841  * @param sender_address address of the other peer, NULL if other peer
842  *                       connected to us
843  * @param sender_address_len number of bytes in sender_address
844  * @return GNUNET_OK if the message was well-formed, GNUNET_SYSERR if not
845  */
846 int
847 GST_neighbours_handle_disconnect (const struct GNUNET_PeerIdentity *sender,
848                                   const struct GNUNET_MessageHeader *hdr,
849                                   const char *plugin_name,
850                                   const void *sender_address,
851                                   size_t sender_address_len)
852 {
853   return GNUNET_SYSERR;
854 }
855
856
857 /* end of file gnunet-service-transport_neighbours.c */