diff options
author | Bart Polot <bart@net.in.tum.de> | 2013-10-04 09:13:35 +0000 |
---|---|---|
committer | Bart Polot <bart@net.in.tum.de> | 2013-10-04 09:13:35 +0000 |
commit | b4f52cedf1afd0e53b2f205f2e543a7900b385be (patch) | |
tree | 08ad81a6a7fd832f420e0e659eefee0e81735433 | |
parent | b5131d91c2abf066d1725f95e043d014150c7b5d (diff) | |
download | gnunet-b4f52cedf1afd0e53b2f205f2e543a7900b385be.tar.gz gnunet-b4f52cedf1afd0e53b2f205f2e543a7900b385be.zip |
- sync
-rw-r--r-- | src/mesh/gnunet-service-mesh-enc.c | 459 | ||||
-rw-r--r-- | src/mesh/gnunet-service-mesh_dht.c | 13 | ||||
-rw-r--r-- | src/mesh/gnunet-service-mesh_dht.h | 6 | ||||
-rw-r--r-- | src/mesh/gnunet-service-mesh_peer.c | 458 |
4 files changed, 471 insertions, 465 deletions
diff --git a/src/mesh/gnunet-service-mesh-enc.c b/src/mesh/gnunet-service-mesh-enc.c index dc053639d..4fef1905e 100644 --- a/src/mesh/gnunet-service-mesh-enc.c +++ b/src/mesh/gnunet-service-mesh-enc.c | |||
@@ -913,462 +913,6 @@ send_core_connection_ack (struct MeshConnection *c, size_t size, void *buf) | |||
913 | return sizeof (struct GNUNET_MESH_ConnectionACK); | 913 | return sizeof (struct GNUNET_MESH_ConnectionACK); |
914 | } | 914 | } |
915 | 915 | ||
916 | |||
917 | /** | ||
918 | * Destroy the peer_info and free any allocated resources linked to it | ||
919 | * | ||
920 | * @param peer The peer_info to destroy. | ||
921 | * | ||
922 | * @return GNUNET_OK on success | ||
923 | */ | ||
924 | static int | ||
925 | peer_destroy (struct MeshPeer *peer) | ||
926 | { | ||
927 | struct GNUNET_PeerIdentity id; | ||
928 | struct MeshPeerPath *p; | ||
929 | struct MeshPeerPath *nextp; | ||
930 | |||
931 | GNUNET_PEER_resolve (peer->id, &id); | ||
932 | GNUNET_PEER_change_rc (peer->id, -1); | ||
933 | |||
934 | if (GNUNET_YES != | ||
935 | GNUNET_CONTAINER_multipeermap_remove (peers, &id, peer)) | ||
936 | { | ||
937 | GNUNET_break (0); | ||
938 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
939 | "removing peer %s, not in peermap\n", GNUNET_i2s (&id)); | ||
940 | } | ||
941 | if (NULL != peer->dhtget) | ||
942 | { | ||
943 | GNUNET_DHT_get_stop (peer->dhtget); | ||
944 | } | ||
945 | p = peer->path_head; | ||
946 | while (NULL != p) | ||
947 | { | ||
948 | nextp = p->next; | ||
949 | GNUNET_CONTAINER_DLL_remove (peer->path_head, peer->path_tail, p); | ||
950 | path_destroy (p); | ||
951 | p = nextp; | ||
952 | } | ||
953 | tunnel_destroy_empty (peer->tunnel); | ||
954 | GNUNET_free (peer); | ||
955 | return GNUNET_OK; | ||
956 | } | ||
957 | |||
958 | |||
959 | /** | ||
960 | * Returns if peer is used (has a tunnel, is neighbor). | ||
961 | * | ||
962 | * @peer Peer to check. | ||
963 | * | ||
964 | * @return GNUNET_YES if peer is in use. | ||
965 | */ | ||
966 | static int | ||
967 | peer_is_used (struct MeshPeer *peer) | ||
968 | { | ||
969 | struct MeshPeerPath *p; | ||
970 | |||
971 | if (NULL != peer->tunnel) | ||
972 | return GNUNET_YES; | ||
973 | |||
974 | for (p = peer->path_head; NULL != p; p = p->next) | ||
975 | { | ||
976 | if (p->length < 3) | ||
977 | return GNUNET_YES; | ||
978 | } | ||
979 | return GNUNET_NO; | ||
980 | } | ||
981 | |||
982 | |||
983 | /** | ||
984 | * Iterator over all the peers to get the oldest timestamp. | ||
985 | * | ||
986 | * @param cls Closure (unsued). | ||
987 | * @param key ID of the peer. | ||
988 | * @param value Peer_Info of the peer. | ||
989 | */ | ||
990 | static int | ||
991 | peer_get_oldest (void *cls, | ||
992 | const struct GNUNET_PeerIdentity *key, | ||
993 | void *value) | ||
994 | { | ||
995 | struct MeshPeer *p = value; | ||
996 | struct GNUNET_TIME_Absolute *abs = cls; | ||
997 | |||
998 | /* Don't count active peers */ | ||
999 | if (GNUNET_YES == peer_is_used (p)) | ||
1000 | return GNUNET_YES; | ||
1001 | |||
1002 | if (abs->abs_value_us < p->last_contact.abs_value_us) | ||
1003 | abs->abs_value_us = p->last_contact.abs_value_us; | ||
1004 | |||
1005 | return GNUNET_YES; | ||
1006 | } | ||
1007 | |||
1008 | |||
1009 | /** | ||
1010 | * Iterator over all the peers to remove the oldest entry. | ||
1011 | * | ||
1012 | * @param cls Closure (unsued). | ||
1013 | * @param key ID of the peer. | ||
1014 | * @param value Peer_Info of the peer. | ||
1015 | */ | ||
1016 | static int | ||
1017 | peer_timeout (void *cls, | ||
1018 | const struct GNUNET_PeerIdentity *key, | ||
1019 | void *value) | ||
1020 | { | ||
1021 | struct MeshPeer *p = value; | ||
1022 | struct GNUNET_TIME_Absolute *abs = cls; | ||
1023 | |||
1024 | if (p->last_contact.abs_value_us == abs->abs_value_us && | ||
1025 | GNUNET_NO == peer_is_used (p)) | ||
1026 | { | ||
1027 | peer_destroy (p); | ||
1028 | return GNUNET_NO; | ||
1029 | } | ||
1030 | return GNUNET_YES; | ||
1031 | } | ||
1032 | |||
1033 | |||
1034 | /** | ||
1035 | * Delete oldest unused peer. | ||
1036 | */ | ||
1037 | static void | ||
1038 | peer_delete_oldest (void) | ||
1039 | { | ||
1040 | struct GNUNET_TIME_Absolute abs; | ||
1041 | |||
1042 | abs = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
1043 | |||
1044 | GNUNET_CONTAINER_multipeermap_iterate (peers, | ||
1045 | &peer_get_oldest, | ||
1046 | &abs); | ||
1047 | GNUNET_CONTAINER_multipeermap_iterate (peers, | ||
1048 | &peer_timeout, | ||
1049 | &abs); | ||
1050 | } | ||
1051 | |||
1052 | |||
1053 | /** | ||
1054 | * Retrieve the MeshPeer stucture associated with the peer, create one | ||
1055 | * and insert it in the appropriate structures if the peer is not known yet. | ||
1056 | * | ||
1057 | * @param peer Full identity of the peer. | ||
1058 | * | ||
1059 | * @return Existing or newly created peer info. | ||
1060 | */ | ||
1061 | static struct MeshPeer * | ||
1062 | peer_get (const struct GNUNET_PeerIdentity *peer_id) | ||
1063 | { | ||
1064 | struct MeshPeer *peer; | ||
1065 | |||
1066 | peer = GNUNET_CONTAINER_multipeermap_get (peers, peer_id); | ||
1067 | if (NULL == peer) | ||
1068 | { | ||
1069 | peer = GNUNET_new (struct MeshPeer); | ||
1070 | if (GNUNET_CONTAINER_multipeermap_size (peers) > max_peers) | ||
1071 | { | ||
1072 | peer_delete_oldest (); | ||
1073 | } | ||
1074 | GNUNET_CONTAINER_multipeermap_put (peers, peer_id, peer, | ||
1075 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); | ||
1076 | peer->id = GNUNET_PEER_intern (peer_id); | ||
1077 | } | ||
1078 | peer->last_contact = GNUNET_TIME_absolute_get(); | ||
1079 | |||
1080 | return peer; | ||
1081 | } | ||
1082 | |||
1083 | |||
1084 | /** | ||
1085 | * Retrieve the MeshPeer stucture associated with the peer, create one | ||
1086 | * and insert it in the appropriate structures if the peer is not known yet. | ||
1087 | * | ||
1088 | * @param peer Short identity of the peer. | ||
1089 | * | ||
1090 | * @return Existing or newly created peer info. | ||
1091 | */ | ||
1092 | static struct MeshPeer * | ||
1093 | peer_get_short (const GNUNET_PEER_Id peer) | ||
1094 | { | ||
1095 | return peer_get (GNUNET_PEER_resolve2 (peer)); | ||
1096 | } | ||
1097 | |||
1098 | |||
1099 | /** | ||
1100 | * Get a cost of a path for a peer considering existing tunnel connections. | ||
1101 | * | ||
1102 | * @param peer Peer towards which the path is considered. | ||
1103 | * @param path Candidate path. | ||
1104 | * | ||
1105 | * @return Cost of the path (path length + number of overlapping nodes) | ||
1106 | */ | ||
1107 | static unsigned int | ||
1108 | peer_get_path_cost (const struct MeshPeer *peer, | ||
1109 | const struct MeshPeerPath *path) | ||
1110 | { | ||
1111 | struct MeshConnection *c; | ||
1112 | unsigned int overlap; | ||
1113 | unsigned int i; | ||
1114 | unsigned int j; | ||
1115 | |||
1116 | if (NULL == path) | ||
1117 | return 0; | ||
1118 | |||
1119 | overlap = 0; | ||
1120 | GNUNET_assert (NULL != peer->tunnel); | ||
1121 | |||
1122 | for (i = 0; i < path->length; i++) | ||
1123 | { | ||
1124 | for (c = peer->tunnel->connection_head; NULL != c; c = c->next) | ||
1125 | { | ||
1126 | for (j = 0; j < c->path->length; j++) | ||
1127 | { | ||
1128 | if (path->peers[i] == c->path->peers[j]) | ||
1129 | { | ||
1130 | overlap++; | ||
1131 | break; | ||
1132 | } | ||
1133 | } | ||
1134 | } | ||
1135 | } | ||
1136 | return (path->length + overlap) * (path->score * -1); | ||
1137 | } | ||
1138 | |||
1139 | |||
1140 | /** | ||
1141 | * Choose the best path towards a peer considering the tunnel properties. | ||
1142 | * | ||
1143 | * @param peer The destination peer. | ||
1144 | * | ||
1145 | * @return Best current known path towards the peer, if any. | ||
1146 | */ | ||
1147 | static struct MeshPeerPath * | ||
1148 | peer_get_best_path (const struct MeshPeer *peer) | ||
1149 | { | ||
1150 | struct MeshPeerPath *best_p; | ||
1151 | struct MeshPeerPath *p; | ||
1152 | struct MeshConnection *c; | ||
1153 | unsigned int best_cost; | ||
1154 | unsigned int cost; | ||
1155 | |||
1156 | best_cost = UINT_MAX; | ||
1157 | best_p = NULL; | ||
1158 | for (p = peer->path_head; NULL != p; p = p->next) | ||
1159 | { | ||
1160 | for (c = peer->tunnel->connection_head; NULL != c; c = c->next) | ||
1161 | if (c->path == p) | ||
1162 | break; | ||
1163 | if (NULL != c) | ||
1164 | continue; /* If path is in use in a connection, skip it. */ | ||
1165 | |||
1166 | if ((cost = peer_get_path_cost (peer, p)) < best_cost) | ||
1167 | { | ||
1168 | best_cost = cost; | ||
1169 | best_p = p; | ||
1170 | } | ||
1171 | } | ||
1172 | return best_p; | ||
1173 | } | ||
1174 | |||
1175 | |||
1176 | |||
1177 | /** | ||
1178 | * Try to establish a new connection to this peer in the given tunnel. | ||
1179 | * If the peer doesn't have any path to it yet, try to get one. | ||
1180 | * If the peer already has some path, send a CREATE CONNECTION towards it. | ||
1181 | * | ||
1182 | * @param peer PeerInfo of the peer. | ||
1183 | */ | ||
1184 | static void | ||
1185 | peer_connect (struct MeshPeer *peer) | ||
1186 | { | ||
1187 | struct MeshTunnel2 *t; | ||
1188 | struct MeshPeerPath *p; | ||
1189 | struct MeshConnection *c; | ||
1190 | int rerun_dhtget; | ||
1191 | |||
1192 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1193 | "peer_connect towards %s\n", | ||
1194 | peer2s (peer)); | ||
1195 | t = peer->tunnel; | ||
1196 | c = NULL; | ||
1197 | rerun_dhtget = GNUNET_NO; | ||
1198 | |||
1199 | if (NULL != peer->path_head) | ||
1200 | { | ||
1201 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "path exists\n"); | ||
1202 | p = peer_get_best_path (peer); | ||
1203 | if (NULL != p) | ||
1204 | { | ||
1205 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " %u hops\n", p->length); | ||
1206 | c = tunnel_use_path (t, p); | ||
1207 | if (NULL == c) | ||
1208 | { | ||
1209 | /* This case can happen when the path includes a first hop that is | ||
1210 | * not yet known to be connected. | ||
1211 | * | ||
1212 | * This happens quite often during testing when running mesh | ||
1213 | * under valgrind: core connect notifications come very late and the | ||
1214 | * DHT result has already come and created a valid path. | ||
1215 | * In this case, the peer->connections hashmap will be NULL and | ||
1216 | * tunnel_use_path will not be able to create a connection from that | ||
1217 | * path. | ||
1218 | * | ||
1219 | * Re-running the DHT GET should give core time to callback. | ||
1220 | */ | ||
1221 | GNUNET_break(0); | ||
1222 | rerun_dhtget = GNUNET_YES; | ||
1223 | } | ||
1224 | else | ||
1225 | { | ||
1226 | send_connection_create (c); | ||
1227 | return; | ||
1228 | } | ||
1229 | } | ||
1230 | } | ||
1231 | |||
1232 | if (NULL != peer->dhtget && GNUNET_YES == rerun_dhtget) | ||
1233 | { | ||
1234 | GNUNET_DHT_get_stop (peer->dhtget); | ||
1235 | peer->dhtget = NULL; | ||
1236 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1237 | " Stopping DHT GET for peer %s\n", peer2s (peer)); | ||
1238 | } | ||
1239 | |||
1240 | if (NULL == peer->dhtget) | ||
1241 | { | ||
1242 | const struct GNUNET_PeerIdentity *id; | ||
1243 | struct GNUNET_HashCode phash; | ||
1244 | |||
1245 | id = GNUNET_PEER_resolve2 (peer->id); | ||
1246 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1247 | " Starting DHT GET for peer %s\n", peer2s (peer)); | ||
1248 | GNUNET_CRYPTO_hash (&id, sizeof (struct GNUNET_PeerIdentity), &phash); | ||
1249 | peer->dhtget = GNUNET_DHT_get_start (dht_handle, /* handle */ | ||
1250 | GNUNET_BLOCK_TYPE_MESH_PEER, /* type */ | ||
1251 | &phash, /* key to search */ | ||
1252 | dht_replication_level, /* replication level */ | ||
1253 | GNUNET_DHT_RO_RECORD_ROUTE | | ||
1254 | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, | ||
1255 | NULL, /* xquery */ | ||
1256 | 0, /* xquery bits */ | ||
1257 | &dht_get_id_handler, peer); | ||
1258 | if (MESH_TUNNEL_NEW == t->state) | ||
1259 | tunnel_change_state (t, MESH_TUNNEL_SEARCHING); | ||
1260 | } | ||
1261 | } | ||
1262 | |||
1263 | |||
1264 | |||
1265 | /** | ||
1266 | * Add the path to the peer and update the path used to reach it in case this | ||
1267 | * is the shortest. | ||
1268 | * | ||
1269 | * @param peer_info Destination peer to add the path to. | ||
1270 | * @param path New path to add. Last peer must be the peer in arg 1. | ||
1271 | * Path will be either used of freed if already known. | ||
1272 | * @param trusted Do we trust that this path is real? | ||
1273 | */ | ||
1274 | void | ||
1275 | peer_add_path (struct MeshPeer *peer_info, struct MeshPeerPath *path, | ||
1276 | int trusted) | ||
1277 | { | ||
1278 | struct MeshPeerPath *aux; | ||
1279 | unsigned int l; | ||
1280 | unsigned int l2; | ||
1281 | |||
1282 | if ((NULL == peer_info) || (NULL == path)) | ||
1283 | { | ||
1284 | GNUNET_break (0); | ||
1285 | path_destroy (path); | ||
1286 | return; | ||
1287 | } | ||
1288 | if (path->peers[path->length - 1] != peer_info->id) | ||
1289 | { | ||
1290 | GNUNET_break (0); | ||
1291 | path_destroy (path); | ||
1292 | return; | ||
1293 | } | ||
1294 | if (2 >= path->length && GNUNET_NO == trusted) | ||
1295 | { | ||
1296 | /* Only allow CORE to tell us about direct paths */ | ||
1297 | path_destroy (path); | ||
1298 | return; | ||
1299 | } | ||
1300 | for (l = 1; l < path->length; l++) | ||
1301 | { | ||
1302 | if (path->peers[l] == myid) | ||
1303 | { | ||
1304 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shortening path by %u\n", l); | ||
1305 | for (l2 = 0; l2 < path->length - l; l2++) | ||
1306 | { | ||
1307 | path->peers[l2] = path->peers[l + l2]; | ||
1308 | } | ||
1309 | path->length -= l; | ||
1310 | l = 1; | ||
1311 | path->peers = | ||
1312 | GNUNET_realloc (path->peers, path->length * sizeof (GNUNET_PEER_Id)); | ||
1313 | } | ||
1314 | } | ||
1315 | |||
1316 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "adding path [%u] to peer %s\n", | ||
1317 | path->length, peer2s (peer_info)); | ||
1318 | |||
1319 | l = path_get_length (path); | ||
1320 | if (0 == l) | ||
1321 | { | ||
1322 | path_destroy (path); | ||
1323 | return; | ||
1324 | } | ||
1325 | |||
1326 | GNUNET_assert (peer_info->id == path->peers[path->length - 1]); | ||
1327 | for (aux = peer_info->path_head; aux != NULL; aux = aux->next) | ||
1328 | { | ||
1329 | l2 = path_get_length (aux); | ||
1330 | if (l2 > l) | ||
1331 | { | ||
1332 | GNUNET_CONTAINER_DLL_insert_before (peer_info->path_head, | ||
1333 | peer_info->path_tail, aux, path); | ||
1334 | return; | ||
1335 | } | ||
1336 | else | ||
1337 | { | ||
1338 | if (l2 == l && memcmp (path->peers, aux->peers, l) == 0) | ||
1339 | { | ||
1340 | path_destroy (path); | ||
1341 | return; | ||
1342 | } | ||
1343 | } | ||
1344 | } | ||
1345 | GNUNET_CONTAINER_DLL_insert_tail (peer_info->path_head, peer_info->path_tail, | ||
1346 | path); | ||
1347 | return; | ||
1348 | } | ||
1349 | |||
1350 | |||
1351 | /** | ||
1352 | * Add the path to the origin peer and update the path used to reach it in case | ||
1353 | * this is the shortest. | ||
1354 | * The path is given in peer_info -> destination, therefore we turn the path | ||
1355 | * upside down first. | ||
1356 | * | ||
1357 | * @param peer_info Peer to add the path to, being the origin of the path. | ||
1358 | * @param path New path to add after being inversed. | ||
1359 | * Path will be either used or freed. | ||
1360 | * @param trusted Do we trust that this path is real? | ||
1361 | */ | ||
1362 | static void | ||
1363 | peer_add_path_to_origin (struct MeshPeer *peer_info, | ||
1364 | struct MeshPeerPath *path, int trusted) | ||
1365 | { | ||
1366 | if (NULL == path) | ||
1367 | return; | ||
1368 | path_invert (path); | ||
1369 | peer_add_path (peer_info, path, trusted); | ||
1370 | } | ||
1371 | |||
1372 | /** | 916 | /** |
1373 | * Build a PeerPath from the paths returned from the DHT, reversing the paths | 917 | * Build a PeerPath from the paths returned from the DHT, reversing the paths |
1374 | * to obtain a local peer -> destination path and interning the peer ids. | 918 | * to obtain a local peer -> destination path and interning the peer ids. |
@@ -2630,9 +2174,8 @@ run (void *cls, struct GNUNET_SERVER_Handle *server, | |||
2630 | GML_init (server); /* Local clients */ | 2174 | GML_init (server); /* Local clients */ |
2631 | GMC_init (c); /* Connections */ | 2175 | GMC_init (c); /* Connections */ |
2632 | GMP_init (c); /* Peers */ | 2176 | GMP_init (c); /* Peers */ |
2633 | GMD_init (c); /* DHT */ | 2177 | GMD_init (c, &my_full_id); /* DHT */ |
2634 | 2178 | ||
2635 | announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, cls); | ||
2636 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Mesh service running\n"); | 2179 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Mesh service running\n"); |
2637 | } | 2180 | } |
2638 | 2181 | ||
diff --git a/src/mesh/gnunet-service-mesh_dht.c b/src/mesh/gnunet-service-mesh_dht.c index 710b95f45..7f8450637 100644 --- a/src/mesh/gnunet-service-mesh_dht.c +++ b/src/mesh/gnunet-service-mesh_dht.c | |||
@@ -103,10 +103,10 @@ announce_id (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
103 | * - Set data expiration in function of X | 103 | * - Set data expiration in function of X |
104 | * - Adapt X to churn | 104 | * - Adapt X to churn |
105 | */ | 105 | */ |
106 | DEBUG_DHT ("DHT_put for ID %s started.\n", GNUNET_i2s (&my_full_id)); | 106 | DEBUG_DHT ("DHT_put for ID %s started.\n", GNUNET_i2s (id)); |
107 | 107 | ||
108 | block.id = my_full_id; | 108 | block.id = *id; |
109 | GNUNET_CRYPTO_hash (&my_full_id, sizeof (struct GNUNET_PeerIdentity), &phash); | 109 | GNUNET_CRYPTO_hash (id, sizeof (struct GNUNET_PeerIdentity), &phash); |
110 | GNUNET_DHT_put (dht_handle, /* DHT handle */ | 110 | GNUNET_DHT_put (dht_handle, /* DHT handle */ |
111 | &phash, /* Key to use */ | 111 | &phash, /* Key to use */ |
112 | dht_replication_level, /* Replication level */ | 112 | dht_replication_level, /* Replication level */ |
@@ -131,10 +131,13 @@ announce_id (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
131 | * Initialize the DHT subsystem. | 131 | * Initialize the DHT subsystem. |
132 | * | 132 | * |
133 | * @param c Configuration. | 133 | * @param c Configuration. |
134 | * @param peer_id Local peer ID (must remain valid during all execution time). | ||
134 | */ | 135 | */ |
135 | void | 136 | void |
136 | GMD_init (const struct GNUNET_CONFIGURATION_Handle *c) | 137 | GMD_init (const struct GNUNET_CONFIGURATION_Handle *c, |
138 | struct GNUNET_PeerIdentity *peer_id) | ||
137 | { | 139 | { |
140 | id = peer_id; | ||
138 | if (GNUNET_OK != | 141 | if (GNUNET_OK != |
139 | GNUNET_CONFIGURATION_get_value_number (c, "MESH", "DHT_REPLICATION_LEVEL", | 142 | GNUNET_CONFIGURATION_get_value_number (c, "MESH", "DHT_REPLICATION_LEVEL", |
140 | &dht_replication_level)) | 143 | &dht_replication_level)) |
@@ -160,7 +163,7 @@ GMD_init (const struct GNUNET_CONFIGURATION_Handle *c) | |||
160 | GNUNET_break (0); | 163 | GNUNET_break (0); |
161 | } | 164 | } |
162 | 165 | ||
163 | announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, cls); | 166 | announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, NULL); |
164 | } | 167 | } |
165 | 168 | ||
166 | 169 | ||
diff --git a/src/mesh/gnunet-service-mesh_dht.h b/src/mesh/gnunet-service-mesh_dht.h index d491020bf..c19cba8b9 100644 --- a/src/mesh/gnunet-service-mesh_dht.h +++ b/src/mesh/gnunet-service-mesh_dht.h | |||
@@ -46,12 +46,14 @@ extern "C" | |||
46 | /******************************************************************************/ | 46 | /******************************************************************************/ |
47 | 47 | ||
48 | /** | 48 | /** |
49 | * Initialize DHT subsystem. | 49 | * Initialize the DHT subsystem. |
50 | * | 50 | * |
51 | * @param c Configuration. | 51 | * @param c Configuration. |
52 | * @param peer_id Local peer ID (must remain valid during all execution time). | ||
52 | */ | 53 | */ |
53 | void | 54 | void |
54 | GMD_init (const struct GNUNET_CONFIGURATION_Handle *c); | 55 | GMD_init (const struct GNUNET_CONFIGURATION_Handle *c, |
56 | struct GNUNET_PeerIdentity *peer_id); | ||
55 | 57 | ||
56 | /** | 58 | /** |
57 | * Shut down the DHT subsystem. | 59 | * Shut down the DHT subsystem. |
diff --git a/src/mesh/gnunet-service-mesh_peer.c b/src/mesh/gnunet-service-mesh_peer.c index 904e1957e..13dc05c65 100644 --- a/src/mesh/gnunet-service-mesh_peer.c +++ b/src/mesh/gnunet-service-mesh_peer.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include "gnunet_util_lib.h" | 23 | #include "gnunet_util_lib.h" |
24 | 24 | ||
25 | #include "gnunet-service-mesh_peer.h" | 25 | #include "gnunet-service-mesh_peer.h" |
26 | #include "mesh_path.h" | ||
26 | 27 | ||
27 | /******************************************************************************/ | 28 | /******************************************************************************/ |
28 | /******************************** STRUCTS **********************************/ | 29 | /******************************** STRUCTS **********************************/ |
@@ -132,6 +133,463 @@ shutdown_tunnel (void *cls, | |||
132 | } | 133 | } |
133 | 134 | ||
134 | 135 | ||
136 | |||
137 | /** | ||
138 | * Destroy the peer_info and free any allocated resources linked to it | ||
139 | * | ||
140 | * @param peer The peer_info to destroy. | ||
141 | * | ||
142 | * @return GNUNET_OK on success | ||
143 | */ | ||
144 | static int | ||
145 | peer_destroy (struct MeshPeer *peer) | ||
146 | { | ||
147 | struct GNUNET_PeerIdentity id; | ||
148 | struct MeshPeerPath *p; | ||
149 | struct MeshPeerPath *nextp; | ||
150 | |||
151 | GNUNET_PEER_resolve (peer->id, &id); | ||
152 | GNUNET_PEER_change_rc (peer->id, -1); | ||
153 | |||
154 | if (GNUNET_YES != | ||
155 | GNUNET_CONTAINER_multipeermap_remove (peers, &id, peer)) | ||
156 | { | ||
157 | GNUNET_break (0); | ||
158 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
159 | "removing peer %s, not in peermap\n", GNUNET_i2s (&id)); | ||
160 | } | ||
161 | if (NULL != peer->dhtget) | ||
162 | { | ||
163 | GNUNET_DHT_get_stop (peer->dhtget); | ||
164 | } | ||
165 | p = peer->path_head; | ||
166 | while (NULL != p) | ||
167 | { | ||
168 | nextp = p->next; | ||
169 | GNUNET_CONTAINER_DLL_remove (peer->path_head, peer->path_tail, p); | ||
170 | path_destroy (p); | ||
171 | p = nextp; | ||
172 | } | ||
173 | tunnel_destroy_empty (peer->tunnel); | ||
174 | GNUNET_free (peer); | ||
175 | return GNUNET_OK; | ||
176 | } | ||
177 | |||
178 | |||
179 | /** | ||
180 | * Returns if peer is used (has a tunnel, is neighbor). | ||
181 | * | ||
182 | * @peer Peer to check. | ||
183 | * | ||
184 | * @return GNUNET_YES if peer is in use. | ||
185 | */ | ||
186 | static int | ||
187 | peer_is_used (struct MeshPeer *peer) | ||
188 | { | ||
189 | struct MeshPeerPath *p; | ||
190 | |||
191 | if (NULL != peer->tunnel) | ||
192 | return GNUNET_YES; | ||
193 | |||
194 | for (p = peer->path_head; NULL != p; p = p->next) | ||
195 | { | ||
196 | if (p->length < 3) | ||
197 | return GNUNET_YES; | ||
198 | } | ||
199 | return GNUNET_NO; | ||
200 | } | ||
201 | |||
202 | |||
203 | /** | ||
204 | * Iterator over all the peers to get the oldest timestamp. | ||
205 | * | ||
206 | * @param cls Closure (unsued). | ||
207 | * @param key ID of the peer. | ||
208 | * @param value Peer_Info of the peer. | ||
209 | */ | ||
210 | static int | ||
211 | peer_get_oldest (void *cls, | ||
212 | const struct GNUNET_PeerIdentity *key, | ||
213 | void *value) | ||
214 | { | ||
215 | struct MeshPeer *p = value; | ||
216 | struct GNUNET_TIME_Absolute *abs = cls; | ||
217 | |||
218 | /* Don't count active peers */ | ||
219 | if (GNUNET_YES == peer_is_used (p)) | ||
220 | return GNUNET_YES; | ||
221 | |||
222 | if (abs->abs_value_us < p->last_contact.abs_value_us) | ||
223 | abs->abs_value_us = p->last_contact.abs_value_us; | ||
224 | |||
225 | return GNUNET_YES; | ||
226 | } | ||
227 | |||
228 | |||
229 | /** | ||
230 | * Iterator over all the peers to remove the oldest entry. | ||
231 | * | ||
232 | * @param cls Closure (unsued). | ||
233 | * @param key ID of the peer. | ||
234 | * @param value Peer_Info of the peer. | ||
235 | */ | ||
236 | static int | ||
237 | peer_timeout (void *cls, | ||
238 | const struct GNUNET_PeerIdentity *key, | ||
239 | void *value) | ||
240 | { | ||
241 | struct MeshPeer *p = value; | ||
242 | struct GNUNET_TIME_Absolute *abs = cls; | ||
243 | |||
244 | if (p->last_contact.abs_value_us == abs->abs_value_us && | ||
245 | GNUNET_NO == peer_is_used (p)) | ||
246 | { | ||
247 | peer_destroy (p); | ||
248 | return GNUNET_NO; | ||
249 | } | ||
250 | return GNUNET_YES; | ||
251 | } | ||
252 | |||
253 | |||
254 | /** | ||
255 | * Delete oldest unused peer. | ||
256 | */ | ||
257 | static void | ||
258 | peer_delete_oldest (void) | ||
259 | { | ||
260 | struct GNUNET_TIME_Absolute abs; | ||
261 | |||
262 | abs = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
263 | |||
264 | GNUNET_CONTAINER_multipeermap_iterate (peers, | ||
265 | &peer_get_oldest, | ||
266 | &abs); | ||
267 | GNUNET_CONTAINER_multipeermap_iterate (peers, | ||
268 | &peer_timeout, | ||
269 | &abs); | ||
270 | } | ||
271 | |||
272 | |||
273 | /** | ||
274 | * Retrieve the MeshPeer stucture associated with the peer, create one | ||
275 | * and insert it in the appropriate structures if the peer is not known yet. | ||
276 | * | ||
277 | * @param peer Full identity of the peer. | ||
278 | * | ||
279 | * @return Existing or newly created peer info. | ||
280 | */ | ||
281 | static struct MeshPeer * | ||
282 | peer_get (const struct GNUNET_PeerIdentity *peer_id) | ||
283 | { | ||
284 | struct MeshPeer *peer; | ||
285 | |||
286 | peer = GNUNET_CONTAINER_multipeermap_get (peers, peer_id); | ||
287 | if (NULL == peer) | ||
288 | { | ||
289 | peer = GNUNET_new (struct MeshPeer); | ||
290 | if (GNUNET_CONTAINER_multipeermap_size (peers) > max_peers) | ||
291 | { | ||
292 | peer_delete_oldest (); | ||
293 | } | ||
294 | GNUNET_CONTAINER_multipeermap_put (peers, peer_id, peer, | ||
295 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); | ||
296 | peer->id = GNUNET_PEER_intern (peer_id); | ||
297 | } | ||
298 | peer->last_contact = GNUNET_TIME_absolute_get(); | ||
299 | |||
300 | return peer; | ||
301 | } | ||
302 | |||
303 | |||
304 | /** | ||
305 | * Retrieve the MeshPeer stucture associated with the peer, create one | ||
306 | * and insert it in the appropriate structures if the peer is not known yet. | ||
307 | * | ||
308 | * @param peer Short identity of the peer. | ||
309 | * | ||
310 | * @return Existing or newly created peer info. | ||
311 | */ | ||
312 | static struct MeshPeer * | ||
313 | peer_get_short (const GNUNET_PEER_Id peer) | ||
314 | { | ||
315 | return peer_get (GNUNET_PEER_resolve2 (peer)); | ||
316 | } | ||
317 | |||
318 | |||
319 | /** | ||
320 | * Get a cost of a path for a peer considering existing tunnel connections. | ||
321 | * | ||
322 | * @param peer Peer towards which the path is considered. | ||
323 | * @param path Candidate path. | ||
324 | * | ||
325 | * @return Cost of the path (path length + number of overlapping nodes) | ||
326 | */ | ||
327 | static unsigned int | ||
328 | peer_get_path_cost (const struct MeshPeer *peer, | ||
329 | const struct MeshPeerPath *path) | ||
330 | { | ||
331 | struct MeshConnection *c; | ||
332 | unsigned int overlap; | ||
333 | unsigned int i; | ||
334 | unsigned int j; | ||
335 | |||
336 | if (NULL == path) | ||
337 | return 0; | ||
338 | |||
339 | overlap = 0; | ||
340 | GNUNET_assert (NULL != peer->tunnel); | ||
341 | |||
342 | for (i = 0; i < path->length; i++) | ||
343 | { | ||
344 | for (c = peer->tunnel->connection_head; NULL != c; c = c->next) | ||
345 | { | ||
346 | for (j = 0; j < c->path->length; j++) | ||
347 | { | ||
348 | if (path->peers[i] == c->path->peers[j]) | ||
349 | { | ||
350 | overlap++; | ||
351 | break; | ||
352 | } | ||
353 | } | ||
354 | } | ||
355 | } | ||
356 | return (path->length + overlap) * (path->score * -1); | ||
357 | } | ||
358 | |||
359 | |||
360 | /** | ||
361 | * Choose the best path towards a peer considering the tunnel properties. | ||
362 | * | ||
363 | * @param peer The destination peer. | ||
364 | * | ||
365 | * @return Best current known path towards the peer, if any. | ||
366 | */ | ||
367 | static struct MeshPeerPath * | ||
368 | peer_get_best_path (const struct MeshPeer *peer) | ||
369 | { | ||
370 | struct MeshPeerPath *best_p; | ||
371 | struct MeshPeerPath *p; | ||
372 | struct MeshConnection *c; | ||
373 | unsigned int best_cost; | ||
374 | unsigned int cost; | ||
375 | |||
376 | best_cost = UINT_MAX; | ||
377 | best_p = NULL; | ||
378 | for (p = peer->path_head; NULL != p; p = p->next) | ||
379 | { | ||
380 | for (c = peer->tunnel->connection_head; NULL != c; c = c->next) | ||
381 | if (c->path == p) | ||
382 | break; | ||
383 | if (NULL != c) | ||
384 | continue; /* If path is in use in a connection, skip it. */ | ||
385 | |||
386 | if ((cost = peer_get_path_cost (peer, p)) < best_cost) | ||
387 | { | ||
388 | best_cost = cost; | ||
389 | best_p = p; | ||
390 | } | ||
391 | } | ||
392 | return best_p; | ||
393 | } | ||
394 | |||
395 | |||
396 | |||
397 | /** | ||
398 | * Try to establish a new connection to this peer in the given tunnel. | ||
399 | * If the peer doesn't have any path to it yet, try to get one. | ||
400 | * If the peer already has some path, send a CREATE CONNECTION towards it. | ||
401 | * | ||
402 | * @param peer PeerInfo of the peer. | ||
403 | */ | ||
404 | static void | ||
405 | peer_connect (struct MeshPeer *peer) | ||
406 | { | ||
407 | struct MeshTunnel2 *t; | ||
408 | struct MeshPeerPath *p; | ||
409 | struct MeshConnection *c; | ||
410 | int rerun_dhtget; | ||
411 | |||
412 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
413 | "peer_connect towards %s\n", | ||
414 | peer2s (peer)); | ||
415 | t = peer->tunnel; | ||
416 | c = NULL; | ||
417 | rerun_dhtget = GNUNET_NO; | ||
418 | |||
419 | if (NULL != peer->path_head) | ||
420 | { | ||
421 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "path exists\n"); | ||
422 | p = peer_get_best_path (peer); | ||
423 | if (NULL != p) | ||
424 | { | ||
425 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " %u hops\n", p->length); | ||
426 | c = tunnel_use_path (t, p); | ||
427 | if (NULL == c) | ||
428 | { | ||
429 | /* This case can happen when the path includes a first hop that is | ||
430 | * not yet known to be connected. | ||
431 | * | ||
432 | * This happens quite often during testing when running mesh | ||
433 | * under valgrind: core connect notifications come very late and the | ||
434 | * DHT result has already come and created a valid path. | ||
435 | * In this case, the peer->connections hashmap will be NULL and | ||
436 | * tunnel_use_path will not be able to create a connection from that | ||
437 | * path. | ||
438 | * | ||
439 | * Re-running the DHT GET should give core time to callback. | ||
440 | */ | ||
441 | GNUNET_break(0); | ||
442 | rerun_dhtget = GNUNET_YES; | ||
443 | } | ||
444 | else | ||
445 | { | ||
446 | send_connection_create (c); | ||
447 | return; | ||
448 | } | ||
449 | } | ||
450 | } | ||
451 | |||
452 | if (NULL != peer->dhtget && GNUNET_YES == rerun_dhtget) | ||
453 | { | ||
454 | GNUNET_DHT_get_stop (peer->dhtget); | ||
455 | peer->dhtget = NULL; | ||
456 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
457 | " Stopping DHT GET for peer %s\n", peer2s (peer)); | ||
458 | } | ||
459 | |||
460 | if (NULL == peer->dhtget) | ||
461 | { | ||
462 | const struct GNUNET_PeerIdentity *id; | ||
463 | struct GNUNET_HashCode phash; | ||
464 | |||
465 | id = GNUNET_PEER_resolve2 (peer->id); | ||
466 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
467 | " Starting DHT GET for peer %s\n", peer2s (peer)); | ||
468 | GNUNET_CRYPTO_hash (&id, sizeof (struct GNUNET_PeerIdentity), &phash); | ||
469 | peer->dhtget = GNUNET_DHT_get_start (dht_handle, /* handle */ | ||
470 | GNUNET_BLOCK_TYPE_MESH_PEER, /* type */ | ||
471 | &phash, /* key to search */ | ||
472 | dht_replication_level, /* replication level */ | ||
473 | GNUNET_DHT_RO_RECORD_ROUTE | | ||
474 | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, | ||
475 | NULL, /* xquery */ | ||
476 | 0, /* xquery bits */ | ||
477 | &dht_get_id_handler, peer); | ||
478 | if (MESH_TUNNEL_NEW == t->state) | ||
479 | tunnel_change_state (t, MESH_TUNNEL_SEARCHING); | ||
480 | } | ||
481 | } | ||
482 | |||
483 | |||
484 | |||
485 | /** | ||
486 | * Add the path to the peer and update the path used to reach it in case this | ||
487 | * is the shortest. | ||
488 | * | ||
489 | * @param peer_info Destination peer to add the path to. | ||
490 | * @param path New path to add. Last peer must be the peer in arg 1. | ||
491 | * Path will be either used of freed if already known. | ||
492 | * @param trusted Do we trust that this path is real? | ||
493 | */ | ||
494 | void | ||
495 | peer_add_path (struct MeshPeer *peer_info, struct MeshPeerPath *path, | ||
496 | int trusted) | ||
497 | { | ||
498 | struct MeshPeerPath *aux; | ||
499 | unsigned int l; | ||
500 | unsigned int l2; | ||
501 | |||
502 | if ((NULL == peer_info) || (NULL == path)) | ||
503 | { | ||
504 | GNUNET_break (0); | ||
505 | path_destroy (path); | ||
506 | return; | ||
507 | } | ||
508 | if (path->peers[path->length - 1] != peer_info->id) | ||
509 | { | ||
510 | GNUNET_break (0); | ||
511 | path_destroy (path); | ||
512 | return; | ||
513 | } | ||
514 | if (2 >= path->length && GNUNET_NO == trusted) | ||
515 | { | ||
516 | /* Only allow CORE to tell us about direct paths */ | ||
517 | path_destroy (path); | ||
518 | return; | ||
519 | } | ||
520 | for (l = 1; l < path->length; l++) | ||
521 | { | ||
522 | if (path->peers[l] == myid) | ||
523 | { | ||
524 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shortening path by %u\n", l); | ||
525 | for (l2 = 0; l2 < path->length - l; l2++) | ||
526 | { | ||
527 | path->peers[l2] = path->peers[l + l2]; | ||
528 | } | ||
529 | path->length -= l; | ||
530 | l = 1; | ||
531 | path->peers = | ||
532 | GNUNET_realloc (path->peers, path->length * sizeof (GNUNET_PEER_Id)); | ||
533 | } | ||
534 | } | ||
535 | |||
536 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "adding path [%u] to peer %s\n", | ||
537 | path->length, peer2s (peer_info)); | ||
538 | |||
539 | l = path_get_length (path); | ||
540 | if (0 == l) | ||
541 | { | ||
542 | path_destroy (path); | ||
543 | return; | ||
544 | } | ||
545 | |||
546 | GNUNET_assert (peer_info->id == path->peers[path->length - 1]); | ||
547 | for (aux = peer_info->path_head; aux != NULL; aux = aux->next) | ||
548 | { | ||
549 | l2 = path_get_length (aux); | ||
550 | if (l2 > l) | ||
551 | { | ||
552 | GNUNET_CONTAINER_DLL_insert_before (peer_info->path_head, | ||
553 | peer_info->path_tail, aux, path); | ||
554 | return; | ||
555 | } | ||
556 | else | ||
557 | { | ||
558 | if (l2 == l && memcmp (path->peers, aux->peers, l) == 0) | ||
559 | { | ||
560 | path_destroy (path); | ||
561 | return; | ||
562 | } | ||
563 | } | ||
564 | } | ||
565 | GNUNET_CONTAINER_DLL_insert_tail (peer_info->path_head, peer_info->path_tail, | ||
566 | path); | ||
567 | return; | ||
568 | } | ||
569 | |||
570 | |||
571 | /** | ||
572 | * Add the path to the origin peer and update the path used to reach it in case | ||
573 | * this is the shortest. | ||
574 | * The path is given in peer_info -> destination, therefore we turn the path | ||
575 | * upside down first. | ||
576 | * | ||
577 | * @param peer_info Peer to add the path to, being the origin of the path. | ||
578 | * @param path New path to add after being inversed. | ||
579 | * Path will be either used or freed. | ||
580 | * @param trusted Do we trust that this path is real? | ||
581 | */ | ||
582 | static void | ||
583 | peer_add_path_to_origin (struct MeshPeer *peer_info, | ||
584 | struct MeshPeerPath *path, int trusted) | ||
585 | { | ||
586 | if (NULL == path) | ||
587 | return; | ||
588 | path_invert (path); | ||
589 | peer_add_path (peer_info, path, trusted); | ||
590 | } | ||
591 | |||
592 | |||
135 | /******************************************************************************/ | 593 | /******************************************************************************/ |
136 | /******************************** API ***********************************/ | 594 | /******************************** API ***********************************/ |
137 | /******************************************************************************/ | 595 | /******************************************************************************/ |