aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBart Polot <bart@net.in.tum.de>2013-10-04 09:13:35 +0000
committerBart Polot <bart@net.in.tum.de>2013-10-04 09:13:35 +0000
commitb4f52cedf1afd0e53b2f205f2e543a7900b385be (patch)
tree08ad81a6a7fd832f420e0e659eefee0e81735433
parentb5131d91c2abf066d1725f95e043d014150c7b5d (diff)
downloadgnunet-b4f52cedf1afd0e53b2f205f2e543a7900b385be.tar.gz
gnunet-b4f52cedf1afd0e53b2f205f2e543a7900b385be.zip
- sync
-rw-r--r--src/mesh/gnunet-service-mesh-enc.c459
-rw-r--r--src/mesh/gnunet-service-mesh_dht.c13
-rw-r--r--src/mesh/gnunet-service-mesh_dht.h6
-rw-r--r--src/mesh/gnunet-service-mesh_peer.c458
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 */
924static int
925peer_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 */
966static int
967peer_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 */
990static int
991peer_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 */
1016static int
1017peer_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 */
1037static void
1038peer_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 */
1061static struct MeshPeer *
1062peer_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 */
1092static struct MeshPeer *
1093peer_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 */
1107static unsigned int
1108peer_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 */
1147static struct MeshPeerPath *
1148peer_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 */
1184static void
1185peer_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 */
1274void
1275peer_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 */
1362static void
1363peer_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 */
135void 136void
136GMD_init (const struct GNUNET_CONFIGURATION_Handle *c) 137GMD_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 */
53void 54void
54GMD_init (const struct GNUNET_CONFIGURATION_Handle *c); 55GMD_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 */
144static int
145peer_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 */
186static int
187peer_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 */
210static int
211peer_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 */
236static int
237peer_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 */
257static void
258peer_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 */
281static struct MeshPeer *
282peer_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 */
312static struct MeshPeer *
313peer_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 */
327static unsigned int
328peer_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 */
367static struct MeshPeerPath *
368peer_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 */
404static void
405peer_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 */
494void
495peer_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 */
582static void
583peer_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/******************************************************************************/