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