aboutsummaryrefslogtreecommitdiff
path: root/src/dv
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2013-03-25 12:47:17 +0000
committerChristian Grothoff <christian@grothoff.org>2013-03-25 12:47:17 +0000
commitee0ee4cc9515917530c6e2a60a8e90349847d4bd (patch)
tree463ec76b9b421333d4bbebe9dcb073e5849d442f /src/dv
parentea69f50952d863c6e7250bc92559a3dca27ce97b (diff)
downloadgnunet-ee0ee4cc9515917530c6e2a60a8e90349847d4bd.tar.gz
gnunet-ee0ee4cc9515917530c6e2a60a8e90349847d4bd.zip
-use ATS from DV
Diffstat (limited to 'src/dv')
-rw-r--r--src/dv/gnunet-service-dv.c353
1 files changed, 238 insertions, 115 deletions
diff --git a/src/dv/gnunet-service-dv.c b/src/dv/gnunet-service-dv.c
index e1a4e2199..1487fc4f6 100644
--- a/src/dv/gnunet-service-dv.c
+++ b/src/dv/gnunet-service-dv.c
@@ -26,9 +26,6 @@
26 * 26 *
27 * @author Christian Grothoff 27 * @author Christian Grothoff
28 * @author Nathan Evans 28 * @author Nathan Evans
29 *
30 * TODO:
31 * - distance updates are not properly communicate to US by core/transport/ats
32 */ 29 */
33#include "platform.h" 30#include "platform.h"
34#include "gnunet_util_lib.h" 31#include "gnunet_util_lib.h"
@@ -38,6 +35,7 @@
38#include "gnunet_peerinfo_service.h" 35#include "gnunet_peerinfo_service.h"
39#include "gnunet_statistics_service.h" 36#include "gnunet_statistics_service.h"
40#include "gnunet_consensus_service.h" 37#include "gnunet_consensus_service.h"
38#include "gnunet_ats_service.h"
41#include "dv.h" 39#include "dv.h"
42#include <gcrypt.h> 40#include <gcrypt.h>
43 41
@@ -237,6 +235,16 @@ struct DirectNeighbor
237 */ 235 */
238 int target_removed; 236 int target_removed;
239 237
238 /**
239 * Our distance to this peer, 0 for unknown.
240 */
241 uint32_t distance;
242
243 /**
244 * Is this neighbor connected at the core level?
245 */
246 int connected;
247
240}; 248};
241 249
242 250
@@ -290,7 +298,9 @@ struct ConsensusSet
290 298
291 299
292/** 300/**
293 * Hashmap of all of our direct neighbors (no DV routing). 301 * Hashmap of all of our neighbors; processing these usually requires
302 * first checking to see if the peer is core-connected and if the
303 * distance is 1, in which case they are direct neighbors.
294 */ 304 */
295static struct GNUNET_CONTAINER_MultiHashMap *direct_neighbors; 305static struct GNUNET_CONTAINER_MultiHashMap *direct_neighbors;
296 306
@@ -332,28 +342,24 @@ static struct GNUNET_SERVER_NotificationContext *nc;
332/** 342/**
333 * Handle for the statistics service. 343 * Handle for the statistics service.
334 */ 344 */
335struct GNUNET_STATISTICS_Handle *stats; 345static struct GNUNET_STATISTICS_Handle *stats;
336
337 346
338/** 347/**
339 * Get distance information from 'atsi'. 348 * Handle to ATS service.
340 *
341 * @param atsi performance data
342 * @param atsi_count number of entries in atsi
343 * @return connected transport distance
344 */ 349 */
345static uint32_t 350static struct GNUNET_ATS_PerformanceHandle *ats;
346get_atsi_distance (const struct GNUNET_ATS_Information *atsi, 351
347 unsigned int atsi_count)
348{
349 unsigned int i;
350 352
351 for (i = 0; i < atsi_count; i++) 353/**
352 if (ntohl (atsi[i].type) == GNUNET_ATS_QUALITY_NET_DISTANCE) 354 * Start creating a new consensus from scratch.
353 return ntohl (atsi->value); 355 *
354 /* FIXME: we do not have distance data? Assume direct neighbor. */ 356 * @param cls the 'struct DirectNeighbor' of the peer we're building
355 return DIRECT_NEIGHBOR_COST; 357 * a routing consensus with
356} 358 * @param tc scheduler context
359 */
360static void
361start_consensus (void *cls,
362 const struct GNUNET_SCHEDULER_TaskContext *tc);
357 363
358 364
359/** 365/**
@@ -696,15 +702,29 @@ move_route (struct Route *route,
696 702
697 703
698/** 704/**
699 * Start creating a new consensus from scratch. 705 * A peer is now connected to us at distance 1. Initiate DV exchange.
700 * 706 *
701 * @param cls the 'struct DirectNeighbor' of the peer we're building 707 * @param neighbor entry for the neighbor at distance 1
702 * a routing consensus with 708 */
703 * @param tc scheduler context
704 */
705static void 709static void
706start_consensus (void *cls, 710handle_direct_connect (struct DirectNeighbor *neighbor)
707 const struct GNUNET_SCHEDULER_TaskContext *tc); 711{
712 struct Route *route;
713
714 GNUNET_STATISTICS_update (stats,
715 "# peers connected (1-hop)",
716 1, GNUNET_NO);
717 route = GNUNET_CONTAINER_multihashmap_get (all_routes,
718 &neighbor->peer.hashPubKey);
719 if (NULL != route)
720 {
721 send_disconnect_to_plugin (&neighbor->peer);
722 release_route (route);
723 GNUNET_free (route);
724 }
725 neighbor->consensus_task = GNUNET_SCHEDULER_add_now (&start_consensus,
726 neighbor);
727}
708 728
709 729
710/** 730/**
@@ -717,26 +737,22 @@ static void
717handle_core_connect (void *cls, const struct GNUNET_PeerIdentity *peer) 737handle_core_connect (void *cls, const struct GNUNET_PeerIdentity *peer)
718{ 738{
719 struct DirectNeighbor *neighbor; 739 struct DirectNeighbor *neighbor;
720 struct Route *route;
721 uint32_t distance;
722 740
723 /* Check for connect to self message */ 741 /* Check for connect to self message */
724 if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity))) 742 if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity)))
725 return; 743 return;
726 fprintf (stderr, "FIX ATS DATA: %s:%u!\n", __FILE__, __LINE__); 744 /* check if entry exists */
727 distance = get_atsi_distance (NULL, 0);
728 neighbor = GNUNET_CONTAINER_multihashmap_get (direct_neighbors, 745 neighbor = GNUNET_CONTAINER_multihashmap_get (direct_neighbors,
729 &peer->hashPubKey); 746 &peer->hashPubKey);
730 if (NULL != neighbor) 747 if (NULL != neighbor)
731 { 748 {
732 GNUNET_break (0); 749 GNUNET_break (GNUNET_YES != neighbor->connected);
750 neighbor->connected = GNUNET_YES;
751 if (DIRECT_NEIGHBOR_COST != neighbor->distance)
752 return;
753 handle_direct_connect (neighbor);
733 return; 754 return;
734 } 755 }
735 if (DIRECT_NEIGHBOR_COST != distance)
736 return; /* is a DV-neighbor */
737 GNUNET_STATISTICS_update (stats,
738 "# peers connected (1-hop)",
739 1, GNUNET_NO);
740 neighbor = GNUNET_malloc (sizeof (struct DirectNeighbor)); 756 neighbor = GNUNET_malloc (sizeof (struct DirectNeighbor));
741 neighbor->peer = *peer; 757 neighbor->peer = *peer;
742 GNUNET_assert (GNUNET_YES == 758 GNUNET_assert (GNUNET_YES ==
@@ -744,16 +760,8 @@ handle_core_connect (void *cls, const struct GNUNET_PeerIdentity *peer)
744 &peer->hashPubKey, 760 &peer->hashPubKey,
745 neighbor, 761 neighbor,
746 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); 762 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
747 route = GNUNET_CONTAINER_multihashmap_get (all_routes, 763 neighbor->connected = GNUNET_YES;
748 &peer->hashPubKey); 764 neighbor->distance = 0; /* unknown */
749 if (NULL != route)
750 {
751 send_disconnect_to_plugin (peer);
752 release_route (route);
753 GNUNET_free (route);
754 }
755 neighbor->consensus_task = GNUNET_SCHEDULER_add_now (&start_consensus,
756 neighbor);
757} 765}
758 766
759 767
@@ -834,6 +842,9 @@ refresh_routes (void *cls, const struct GNUNET_HashCode * key, void *value)
834{ 842{
835 struct DirectNeighbor *neighbor = value; 843 struct DirectNeighbor *neighbor = value;
836 844
845 if ( (GNUNET_YES != neighbor->connected) ||
846 (DIRECT_NEIGHBOR_COST != neighbor->distance) )
847 return GNUNET_YES;
837 if (NULL != neighbor->neighbor_table) 848 if (NULL != neighbor->neighbor_table)
838 GNUNET_CONTAINER_multihashmap_iterate (neighbor->neighbor_table, 849 GNUNET_CONTAINER_multihashmap_iterate (neighbor->neighbor_table,
839 &check_possible_route, 850 &check_possible_route,
@@ -843,6 +854,166 @@ refresh_routes (void *cls, const struct GNUNET_HashCode * key, void *value)
843 854
844 855
845/** 856/**
857 * Get distance information from 'atsi'.
858 *
859 * @param atsi performance data
860 * @param atsi_count number of entries in atsi
861 * @return connected transport distance
862 */
863static uint32_t
864get_atsi_distance (const struct GNUNET_ATS_Information *atsi,
865 uint32_t atsi_count)
866{
867 uint32_t i;
868
869 for (i = 0; i < atsi_count; i++)
870 if (ntohl (atsi[i].type) == GNUNET_ATS_QUALITY_NET_DISTANCE)
871 return ntohl (atsi->value);
872 /* If we do not have explicit distance data, assume direct neighbor. */
873 return DIRECT_NEIGHBOR_COST;
874}
875
876
877/**
878 * Multihashmap iterator for freeing routes that go via a particular
879 * neighbor that disconnected and is thus no longer available.
880 *
881 * @param cls the direct neighbor that is now unavailable
882 * @param key key value stored under
883 * @param value a 'struct Route' that may or may not go via neighbor
884 *
885 * @return GNUNET_YES to continue iteration, GNUNET_NO to stop
886 */
887static int
888cull_routes (void *cls, const struct GNUNET_HashCode * key, void *value)
889{
890 struct DirectNeighbor *neighbor = cls;
891 struct Route *route = value;
892
893 if (route->next_hop != neighbor)
894 return GNUNET_YES; /* not affected */
895 GNUNET_assert (GNUNET_YES ==
896 GNUNET_CONTAINER_multihashmap_remove (all_routes, key, value));
897 release_route (route);
898 send_disconnect_to_plugin (&route->target.peer);
899 GNUNET_free (route);
900 return GNUNET_YES;
901}
902
903
904/**
905 * Handle the case that a direct connection to a peer is
906 * disrupted. Remove all routes via that peer and
907 * stop the consensus with it.
908 *
909 * @param neighbor peer that was disconnected (or at least is no
910 * longer at distance 1)
911 */
912static void
913handle_direct_disconnect (struct DirectNeighbor *neighbor)
914{
915 GNUNET_CONTAINER_multihashmap_iterate (all_routes,
916 &cull_routes,
917 neighbor);
918 if (NULL != neighbor->cth)
919 {
920 GNUNET_CORE_notify_transmit_ready_cancel (neighbor->cth);
921 neighbor->cth = NULL;
922 }
923 if (NULL != neighbor->neighbor_table_consensus)
924 {
925 GNUNET_CONTAINER_multihashmap_iterate (neighbor->neighbor_table_consensus,
926 &free_targets,
927 NULL);
928 GNUNET_CONTAINER_multihashmap_destroy (neighbor->neighbor_table_consensus);
929 neighbor->neighbor_table_consensus = NULL;
930 }
931 if (NULL != neighbor->neighbor_table)
932 {
933 GNUNET_CONTAINER_multihashmap_iterate (neighbor->neighbor_table,
934 &free_targets,
935 NULL);
936 GNUNET_CONTAINER_multihashmap_destroy (neighbor->neighbor_table);
937 neighbor->neighbor_table = NULL;
938 }
939 if (GNUNET_SCHEDULER_NO_TASK != neighbor->consensus_task)
940 {
941 GNUNET_SCHEDULER_cancel (neighbor->consensus_task);
942 neighbor->consensus_task = GNUNET_SCHEDULER_NO_TASK;
943 }
944 if (NULL != neighbor->consensus)
945 {
946 GNUNET_CONSENSUS_destroy (neighbor->consensus);
947 neighbor->consensus = NULL;
948 }
949}
950
951
952/**
953 * Function that is called with QoS information about an address; used
954 * to update our current distance to another peer.
955 *
956 * @param cls closure
957 * @param address the address
958 * @param bandwidth_out assigned outbound bandwidth for the connection
959 * @param bandwidth_in assigned inbound bandwidth for the connection
960 * @param ats performance data for the address (as far as known)
961 * @param ats_count number of performance records in 'ats'
962 */
963static void
964handle_ats_update (void *cls,
965 const struct GNUNET_HELLO_Address *address,
966 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
967 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
968 const struct GNUNET_ATS_Information *ats,
969 uint32_t ats_count)
970{
971 struct DirectNeighbor *neighbor;
972 uint32_t distance;
973
974 /* FIXME: ignore CB if this address is not the one that is in use! */
975 distance = get_atsi_distance (ats, ats_count);
976 /* check if entry exists */
977 neighbor = GNUNET_CONTAINER_multihashmap_get (direct_neighbors,
978 &address->peer.hashPubKey);
979 if (NULL != neighbor)
980 {
981 if ( (DIRECT_NEIGHBOR_COST == neighbor->distance) &&
982 (DIRECT_NEIGHBOR_COST == distance) )
983 return; /* no change */
984 if (DIRECT_NEIGHBOR_COST == neighbor->distance)
985 {
986 neighbor->distance = distance;
987 GNUNET_STATISTICS_update (stats,
988 "# peers connected (1-hop)",
989 -1, GNUNET_NO);
990 handle_direct_disconnect (neighbor);
991 GNUNET_CONTAINER_multihashmap_iterate (direct_neighbors,
992 &refresh_routes,
993 NULL);
994 return;
995 }
996 neighbor->distance = distance;
997 if (DIRECT_NEIGHBOR_COST != neighbor->distance)
998 return;
999 if (GNUNET_YES != neighbor->connected)
1000 return;
1001 handle_direct_connect (neighbor);
1002 return;
1003 }
1004 neighbor = GNUNET_malloc (sizeof (struct DirectNeighbor));
1005 neighbor->peer = address->peer;
1006 GNUNET_assert (GNUNET_YES ==
1007 GNUNET_CONTAINER_multihashmap_put (direct_neighbors,
1008 &address->peer.hashPubKey,
1009 neighbor,
1010 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1011 neighbor->connected = GNUNET_NO; /* not yet */
1012 neighbor->distance = distance;
1013}
1014
1015
1016/**
846 * Check if a target was removed from the set of the other peer; if so, 1017 * Check if a target was removed from the set of the other peer; if so,
847 * if we also used it for our route, we need to remove it from our 1018 * if we also used it for our route, we need to remove it from our
848 * 'all_routes' set (and later check if an alternative path now exists). 1019 * 'all_routes' set (and later check if an alternative path now exists).
@@ -954,7 +1125,6 @@ check_target_added (void *cls,
954 * The consensus has concluded, clean up and schedule the next one. 1125 * The consensus has concluded, clean up and schedule the next one.
955 * 1126 *
956 * @param cls the 'struct GNUNET_DirectNeighbor' with which we created the consensus 1127 * @param cls the 'struct GNUNET_DirectNeighbor' with which we created the consensus
957 * @param group FIXME
958 */ 1128 */
959static void 1129static void
960consensus_done_cb (void *cls) 1130consensus_done_cb (void *cls)
@@ -1282,33 +1452,6 @@ handle_dv_send_message (void *cls, struct GNUNET_SERVER_Client *client,
1282 1452
1283 1453
1284/** 1454/**
1285 * Multihashmap iterator for freeing routes that go via a particular
1286 * neighbor that disconnected and is thus no longer available.
1287 *
1288 * @param cls the direct neighbor that is now unavailable
1289 * @param key key value stored under
1290 * @param value a 'struct Route' that may or may not go via neighbor
1291 *
1292 * @return GNUNET_YES to continue iteration, GNUNET_NO to stop
1293 */
1294static int
1295cull_routes (void *cls, const struct GNUNET_HashCode * key, void *value)
1296{
1297 struct DirectNeighbor *neighbor = cls;
1298 struct Route *route = value;
1299
1300 if (route->next_hop != neighbor)
1301 return GNUNET_YES; /* not affected */
1302 GNUNET_assert (GNUNET_YES ==
1303 GNUNET_CONTAINER_multihashmap_remove (all_routes, key, value));
1304 release_route (route);
1305 send_disconnect_to_plugin (&route->target.peer);
1306 GNUNET_free (route);
1307 return GNUNET_YES;
1308}
1309
1310
1311/**
1312 * Cleanup all of the data structures associated with a given neighbor. 1455 * Cleanup all of the data structures associated with a given neighbor.
1313 * 1456 *
1314 * @param neighbor neighbor to clean up 1457 * @param neighbor neighbor to clean up
@@ -1326,40 +1469,7 @@ cleanup_neighbor (struct DirectNeighbor *neighbor)
1326 pending); 1469 pending);
1327 GNUNET_free (pending); 1470 GNUNET_free (pending);
1328 } 1471 }
1329 GNUNET_CONTAINER_multihashmap_iterate (all_routes, 1472 handle_direct_disconnect (neighbor);
1330 &cull_routes,
1331 neighbor);
1332 if (NULL != neighbor->cth)
1333 {
1334 GNUNET_CORE_notify_transmit_ready_cancel (neighbor->cth);
1335 neighbor->cth = NULL;
1336 }
1337 if (NULL != neighbor->neighbor_table_consensus)
1338 {
1339 GNUNET_CONTAINER_multihashmap_iterate (neighbor->neighbor_table_consensus,
1340 &free_targets,
1341 NULL);
1342 GNUNET_CONTAINER_multihashmap_destroy (neighbor->neighbor_table_consensus);
1343 neighbor->neighbor_table_consensus = NULL;
1344 }
1345 if (NULL != neighbor->neighbor_table)
1346 {
1347 GNUNET_CONTAINER_multihashmap_iterate (neighbor->neighbor_table,
1348 &free_targets,
1349 NULL);
1350 GNUNET_CONTAINER_multihashmap_destroy (neighbor->neighbor_table);
1351 neighbor->neighbor_table = NULL;
1352 }
1353 if (GNUNET_SCHEDULER_NO_TASK != neighbor->consensus_task)
1354 {
1355 GNUNET_SCHEDULER_cancel (neighbor->consensus_task);
1356 neighbor->consensus_task = GNUNET_SCHEDULER_NO_TASK;
1357 }
1358 if (NULL != neighbor->consensus)
1359 {
1360 GNUNET_CONSENSUS_destroy (neighbor->consensus);
1361 neighbor->consensus = NULL;
1362 }
1363 GNUNET_assert (GNUNET_YES == 1473 GNUNET_assert (GNUNET_YES ==
1364 GNUNET_CONTAINER_multihashmap_remove (direct_neighbors, 1474 GNUNET_CONTAINER_multihashmap_remove (direct_neighbors,
1365 &neighbor->peer.hashPubKey, 1475 &neighbor->peer.hashPubKey,
@@ -1389,12 +1499,17 @@ handle_core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
1389 GNUNET_CONTAINER_multihashmap_get (direct_neighbors, &peer->hashPubKey); 1499 GNUNET_CONTAINER_multihashmap_get (direct_neighbors, &peer->hashPubKey);
1390 if (NULL == neighbor) 1500 if (NULL == neighbor)
1391 { 1501 {
1392 /* must have been a DV-neighbor, ignore */ 1502 GNUNET_break (0);
1393 return; 1503 return;
1394 } 1504 }
1395 GNUNET_STATISTICS_update (stats, 1505 GNUNET_break (GNUNET_YES == neighbor->connected);
1396 "# peers connected (1-hop)", 1506 neighbor->connected = GNUNET_NO;
1397 -1, GNUNET_NO); 1507 if (DIRECT_NEIGHBOR_COST == neighbor->distance)
1508 {
1509 GNUNET_STATISTICS_update (stats,
1510 "# peers connected (1-hop)",
1511 -1, GNUNET_NO);
1512 }
1398 cleanup_neighbor (neighbor); 1513 cleanup_neighbor (neighbor);
1399 GNUNET_CONTAINER_multihashmap_iterate (direct_neighbors, 1514 GNUNET_CONTAINER_multihashmap_iterate (direct_neighbors,
1400 &refresh_routes, 1515 &refresh_routes,
@@ -1459,6 +1574,8 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1459 1574
1460 GNUNET_CORE_disconnect (core_api); 1575 GNUNET_CORE_disconnect (core_api);
1461 core_api = NULL; 1576 core_api = NULL;
1577 GNUNET_ATS_performance_done (ats);
1578 ats = NULL;
1462 GNUNET_CONTAINER_multihashmap_iterate (direct_neighbors, 1579 GNUNET_CONTAINER_multihashmap_iterate (direct_neighbors,
1463 &free_direct_neighbors, NULL); 1580 &free_direct_neighbors, NULL);
1464 GNUNET_CONTAINER_multihashmap_iterate (all_routes, 1581 GNUNET_CONTAINER_multihashmap_iterate (all_routes,
@@ -1582,6 +1699,12 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
1582 1699
1583 if (NULL == core_api) 1700 if (NULL == core_api)
1584 return; 1701 return;
1702 ats = GNUNET_ATS_performance_init (cfg, &handle_ats_update, NULL);
1703 if (NULL == ats)
1704 {
1705 GNUNET_CORE_disconnect (core_api);
1706 return;
1707 }
1585 nc = GNUNET_SERVER_notification_context_create (server, 1708 nc = GNUNET_SERVER_notification_context_create (server,
1586 MAX_QUEUE_SIZE_PLUGIN); 1709 MAX_QUEUE_SIZE_PLUGIN);
1587 stats = GNUNET_STATISTICS_create ("dv", cfg); 1710 stats = GNUNET_STATISTICS_create ("dv", cfg);