aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2015-10-25 23:04:09 +0000
committerChristian Grothoff <christian@grothoff.org>2015-10-25 23:04:09 +0000
commita7fbcf1c827ea25046c9f9e5c4e2a567eba72318 (patch)
tree0dd1e0bca0cbbb8add221a70a00b9dc7b51a124c
parenta6d5893f9680dea995b1172f601adc27b2039b75 (diff)
downloadgnunet-a7fbcf1c827ea25046c9f9e5c4e2a567eba72318.tar.gz
gnunet-a7fbcf1c827ea25046c9f9e5c4e2a567eba72318.zip
check against all pending requests with same hash, not just first; this is a true multihashmap
-rw-r--r--src/fs/gnunet-service-fs_cp.c156
-rw-r--r--src/fs/gnunet-service-fs_pr.c19
2 files changed, 120 insertions, 55 deletions
diff --git a/src/fs/gnunet-service-fs_cp.c b/src/fs/gnunet-service-fs_cp.c
index 67338b6ec..0a4c77468 100644
--- a/src/fs/gnunet-service-fs_cp.c
+++ b/src/fs/gnunet-service-fs_cp.c
@@ -815,7 +815,8 @@ free_pending_request (struct PeerRequest *peerreq,
815 -1, GNUNET_NO); 815 -1, GNUNET_NO);
816 GNUNET_break (GNUNET_YES == 816 GNUNET_break (GNUNET_YES ==
817 GNUNET_CONTAINER_multihashmap_remove (cp->request_map, 817 GNUNET_CONTAINER_multihashmap_remove (cp->request_map,
818 query, peerreq)); 818 query,
819 peerreq));
819 GNUNET_free (peerreq); 820 GNUNET_free (peerreq);
820} 821}
821 822
@@ -1181,6 +1182,83 @@ bound_ttl (int32_t ttl_in, uint32_t prio)
1181 1182
1182 1183
1183/** 1184/**
1185 * Closure for #test_exist_cb().
1186 */
1187struct TestExistClosure
1188{
1189
1190 /**
1191 * Priority of the incoming request.
1192 */
1193 int32_t priority;
1194
1195 /**
1196 * Relative TTL of the incoming request.
1197 */
1198 int32_t ttl;
1199
1200 /**
1201 * Type of the incoming request.
1202 */
1203 enum GNUNET_BLOCK_Type type;
1204
1205 /**
1206 * Set to #GNUNET_YES if we are done handling the query.
1207 */
1208 int finished;
1209
1210};
1211
1212
1213/**
1214 * Test if the query already exists. If so, merge it, otherwise
1215 * keep `finished` at #GNUNET_NO.
1216 *
1217 * @param cls our `struct TestExistClosure`
1218 * @param hc the key of the query
1219 * @param value the existing `struct PeerRequest`.
1220 * @return #GNUNET_YES to continue to iterate,
1221 * #GNUNET_NO if we successfully merged
1222 */
1223static int
1224test_exist_cb (void *cls,
1225 const struct GNUNET_HashCode *hc,
1226 void *value)
1227{
1228 struct TestExistClosure *tec = cls;
1229 struct PeerRequest *peerreq = value;
1230 struct GSF_PendingRequest *pr;
1231 struct GSF_PendingRequestData *prd;
1232
1233 pr = peerreq->pr;
1234 prd = GSF_pending_request_get_data_ (pr);
1235 if (prd->type != tec->type)
1236 return GNUNET_YES;
1237 if (prd->ttl.abs_value_us >=
1238 GNUNET_TIME_absolute_get ().abs_value_us + tec->ttl * 1000LL)
1239 {
1240 /* existing request has higher TTL, drop new one! */
1241 prd->priority += tec->priority;
1242 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1243 "Have existing request with higher TTL, dropping new request.\n");
1244 GNUNET_STATISTICS_update (GSF_stats,
1245 gettext_noop
1246 ("# requests dropped due to higher-TTL request"),
1247 1, GNUNET_NO);
1248 tec->finished = GNUNET_YES;
1249 return GNUNET_NO;
1250 }
1251 /* existing request has lower TTL, drop old one! */
1252 tec->priority += prd->priority;
1253 GSF_pending_request_cancel_ (pr, GNUNET_YES);
1254 free_pending_request (peerreq,
1255 hc);
1256 return GNUNET_NO;
1257}
1258
1259
1260
1261/**
1184 * Handle P2P "QUERY" message. Creates the pending request entry 1262 * Handle P2P "QUERY" message. Creates the pending request entry
1185 * and sets up all of the data structures to that we will 1263 * and sets up all of the data structures to that we will
1186 * process replies properly. Does not initiate forwarding or 1264 * process replies properly. Does not initiate forwarding or
@@ -1197,7 +1275,6 @@ GSF_handle_p2p_query_ (const struct GNUNET_PeerIdentity *other,
1197{ 1275{
1198 struct PeerRequest *peerreq; 1276 struct PeerRequest *peerreq;
1199 struct GSF_PendingRequest *pr; 1277 struct GSF_PendingRequest *pr;
1200 struct GSF_PendingRequestData *prd;
1201 struct GSF_ConnectedPeer *cp; 1278 struct GSF_ConnectedPeer *cp;
1202 struct GSF_ConnectedPeer *cps; 1279 struct GSF_ConnectedPeer *cps;
1203 const struct GNUNET_PeerIdentity *target; 1280 const struct GNUNET_PeerIdentity *target;
@@ -1209,9 +1286,7 @@ GSF_handle_p2p_query_ (const struct GNUNET_PeerIdentity *other,
1209 uint32_t bm; 1286 uint32_t bm;
1210 size_t bfsize; 1287 size_t bfsize;
1211 uint32_t ttl_decrement; 1288 uint32_t ttl_decrement;
1212 int32_t priority; 1289 struct TestExistClosure tec;
1213 int32_t ttl;
1214 enum GNUNET_BLOCK_Type type;
1215 GNUNET_PEER_Id spid; 1290 GNUNET_PEER_Id spid;
1216 1291
1217 msize = ntohs (message->size); 1292 msize = ntohs (message->size);
@@ -1226,7 +1301,7 @@ GSF_handle_p2p_query_ (const struct GNUNET_PeerIdentity *other,
1226 1, 1301 1,
1227 GNUNET_NO); 1302 GNUNET_NO);
1228 gm = (const struct GetMessage *) message; 1303 gm = (const struct GetMessage *) message;
1229 type = ntohl (gm->type); 1304 tec.type = ntohl (gm->type);
1230 bm = ntohl (gm->hash_bitmap); 1305 bm = ntohl (gm->hash_bitmap);
1231 bits = 0; 1306 bits = 0;
1232 while (bm > 0) 1307 while (bm > 0)
@@ -1297,9 +1372,9 @@ GSF_handle_p2p_query_ (const struct GNUNET_PeerIdentity *other,
1297 /* note that we can really only check load here since otherwise 1372 /* note that we can really only check load here since otherwise
1298 * peers could find out that we are overloaded by not being 1373 * peers could find out that we are overloaded by not being
1299 * disconnected after sending us a malformed query... */ 1374 * disconnected after sending us a malformed query... */
1300 priority = bound_priority (ntohl (gm->priority), 1375 tec.priority = bound_priority (ntohl (gm->priority),
1301 cps); 1376 cps);
1302 if (priority < 0) 1377 if (tec.priority < 0)
1303 { 1378 {
1304 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1379 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1305 "Dropping query from `%s', this peer is too busy.\n", 1380 "Dropping query from `%s', this peer is too busy.\n",
@@ -1309,7 +1384,7 @@ GSF_handle_p2p_query_ (const struct GNUNET_PeerIdentity *other,
1309 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1384 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1310 "Received request for `%s' of type %u from peer `%s' with flags %u\n", 1385 "Received request for `%s' of type %u from peer `%s' with flags %u\n",
1311 GNUNET_h2s (&gm->query), 1386 GNUNET_h2s (&gm->query),
1312 (unsigned int) type, 1387 (unsigned int) tec.type,
1313 GNUNET_i2s (other), 1388 GNUNET_i2s (other),
1314 (unsigned int) bm); 1389 (unsigned int) bm);
1315 target = 1390 target =
@@ -1317,28 +1392,31 @@ GSF_handle_p2p_query_ (const struct GNUNET_PeerIdentity *other,
1317 (bm & GET_MESSAGE_BIT_TRANSMIT_TO)) ? (&opt[bits++]) : NULL; 1392 (bm & GET_MESSAGE_BIT_TRANSMIT_TO)) ? (&opt[bits++]) : NULL;
1318 options = GSF_PRO_DEFAULTS; 1393 options = GSF_PRO_DEFAULTS;
1319 spid = 0; 1394 spid = 0;
1320 if ((GNUNET_LOAD_get_load (cp->ppd.transmission_delay) > 3 * (1 + priority)) 1395 if ((GNUNET_LOAD_get_load (cp->ppd.transmission_delay) > 3 * (1 + tec.priority))
1321 || (GNUNET_LOAD_get_average (cp->ppd.transmission_delay) > 1396 || (GNUNET_LOAD_get_average (cp->ppd.transmission_delay) >
1322 GNUNET_CONSTANTS_MAX_CORK_DELAY.rel_value_us * 2 + 1397 GNUNET_CONSTANTS_MAX_CORK_DELAY.rel_value_us * 2 +
1323 GNUNET_LOAD_get_average (GSF_rt_entry_lifetime))) 1398 GNUNET_LOAD_get_average (GSF_rt_entry_lifetime)))
1324 { 1399 {
1325 /* don't have BW to send to peer, or would likely take longer than we have for it, 1400 /* don't have BW to send to peer, or would likely take longer than we have for it,
1326 * so at best indirect the query */ 1401 * so at best indirect the query */
1327 priority = 0; 1402 tec.priority = 0;
1328 options |= GSF_PRO_FORWARD_ONLY; 1403 options |= GSF_PRO_FORWARD_ONLY;
1329 spid = GNUNET_PEER_intern (other); 1404 spid = GNUNET_PEER_intern (other);
1330 GNUNET_assert (0 != spid); 1405 GNUNET_assert (0 != spid);
1331 } 1406 }
1332 ttl = bound_ttl (ntohl (gm->ttl), priority); 1407 tec.ttl = bound_ttl (ntohl (gm->ttl),
1408 tec.priority);
1333 /* decrement ttl (always) */ 1409 /* decrement ttl (always) */
1334 ttl_decrement = 1410 ttl_decrement =
1335 2 * TTL_DECREMENT + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1411 2 * TTL_DECREMENT + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1336 TTL_DECREMENT); 1412 TTL_DECREMENT);
1337 if ((ttl < 0) && (((int32_t) (ttl - ttl_decrement)) > 0)) 1413 if ((tec.ttl < 0) && (((int32_t) (tec.ttl - ttl_decrement)) > 0))
1338 { 1414 {
1339 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1415 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1340 "Dropping query from `%s' due to TTL underflow (%d - %u).\n", 1416 "Dropping query from `%s' due to TTL underflow (%d - %u).\n",
1341 GNUNET_i2s (other), ttl, ttl_decrement); 1417 GNUNET_i2s (other),
1418 tec.ttl,
1419 ttl_decrement);
1342 GNUNET_STATISTICS_update (GSF_stats, 1420 GNUNET_STATISTICS_update (GSF_stats,
1343 gettext_noop 1421 gettext_noop
1344 ("# requests dropped due TTL underflow"), 1, 1422 ("# requests dropped due TTL underflow"), 1,
@@ -1346,41 +1424,21 @@ GSF_handle_p2p_query_ (const struct GNUNET_PeerIdentity *other,
1346 /* integer underflow => drop (should be very rare)! */ 1424 /* integer underflow => drop (should be very rare)! */
1347 return NULL; 1425 return NULL;
1348 } 1426 }
1349 ttl -= ttl_decrement; 1427 tec.ttl -= ttl_decrement;
1350 1428
1351 /* test if the request already exists */ 1429 /* test if the request already exists */
1352 peerreq = GNUNET_CONTAINER_multihashmap_get (cp->request_map, 1430 tec.finished = GNUNET_NO;
1353 &gm->query); 1431 GNUNET_CONTAINER_multihashmap_get_multiple (cp->request_map,
1354 if (NULL != peerreq) 1432 &gm->query,
1355 { 1433 &test_exist_cb,
1356 pr = peerreq->pr; 1434 &tec);
1357 prd = GSF_pending_request_get_data_ (pr); 1435 if (GNUNET_YES == tec.finished)
1358 if (prd->type == type) 1436 return NULL; /* merged into existing request, we're done */
1359 {
1360 if (prd->ttl.abs_value_us >= GNUNET_TIME_absolute_get ().abs_value_us + ttl * 1000LL)
1361 {
1362 /* existing request has higher TTL, drop new one! */
1363 prd->priority += priority;
1364 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1365 "Have existing request with higher TTL, dropping new request.\n",
1366 GNUNET_i2s (other));
1367 GNUNET_STATISTICS_update (GSF_stats,
1368 gettext_noop
1369 ("# requests dropped due to higher-TTL request"),
1370 1, GNUNET_NO);
1371 return NULL;
1372 }
1373 /* existing request has lower TTL, drop old one! */
1374 priority += prd->priority;
1375 GSF_pending_request_cancel_ (pr, GNUNET_YES);
1376 free_pending_request (peerreq, &gm->query);
1377 }
1378 }
1379 1437
1380 peerreq = GNUNET_new (struct PeerRequest); 1438 peerreq = GNUNET_new (struct PeerRequest);
1381 peerreq->cp = cp; 1439 peerreq->cp = cp;
1382 pr = GSF_pending_request_create_ (options, 1440 pr = GSF_pending_request_create_ (options,
1383 type, 1441 tec.type,
1384 &gm->query, 1442 &gm->query,
1385 target, 1443 target,
1386 (bfsize > 0) 1444 (bfsize > 0)
@@ -1389,8 +1447,8 @@ GSF_handle_p2p_query_ (const struct GNUNET_PeerIdentity *other,
1389 bfsize, 1447 bfsize,
1390 ntohl (gm->filter_mutator), 1448 ntohl (gm->filter_mutator),
1391 1 /* anonymity */, 1449 1 /* anonymity */,
1392 (uint32_t) priority, 1450 (uint32_t) tec.priority,
1393 ttl, 1451 tec.ttl,
1394 spid, 1452 spid,
1395 GNUNET_PEER_intern (other), 1453 GNUNET_PEER_intern (other),
1396 NULL, 0, /* replies_seen */ 1454 NULL, 0, /* replies_seen */
@@ -1398,7 +1456,8 @@ GSF_handle_p2p_query_ (const struct GNUNET_PeerIdentity *other,
1398 GNUNET_assert (NULL != pr); 1456 GNUNET_assert (NULL != pr);
1399 peerreq->pr = pr; 1457 peerreq->pr = pr;
1400 GNUNET_break (GNUNET_OK == 1458 GNUNET_break (GNUNET_OK ==
1401 GNUNET_CONTAINER_multihashmap_put (cp->request_map, &gm->query, 1459 GNUNET_CONTAINER_multihashmap_put (cp->request_map,
1460 &gm->query,
1402 peerreq, 1461 peerreq,
1403 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); 1462 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
1404 GNUNET_STATISTICS_update (GSF_stats, 1463 GNUNET_STATISTICS_update (GSF_stats,
@@ -1672,7 +1731,8 @@ GSF_peer_disconnect_handler_ (void *cls,
1672 cp->rc_delay_task = NULL; 1731 cp->rc_delay_task = NULL;
1673 } 1732 }
1674 GNUNET_CONTAINER_multihashmap_iterate (cp->request_map, 1733 GNUNET_CONTAINER_multihashmap_iterate (cp->request_map,
1675 &cancel_pending_request, cp); 1734 &cancel_pending_request,
1735 cp);
1676 GNUNET_CONTAINER_multihashmap_destroy (cp->request_map); 1736 GNUNET_CONTAINER_multihashmap_destroy (cp->request_map);
1677 cp->request_map = NULL; 1737 cp->request_map = NULL;
1678 GSF_plan_notify_peer_disconnect_ (cp); 1738 GSF_plan_notify_peer_disconnect_ (cp);
diff --git a/src/fs/gnunet-service-fs_pr.c b/src/fs/gnunet-service-fs_pr.c
index a96610052..187687f17 100644
--- a/src/fs/gnunet-service-fs_pr.c
+++ b/src/fs/gnunet-service-fs_pr.c
@@ -422,10 +422,10 @@ int
422GSF_pending_request_is_compatible_ (struct GSF_PendingRequest *pra, 422GSF_pending_request_is_compatible_ (struct GSF_PendingRequest *pra,
423 struct GSF_PendingRequest *prb) 423 struct GSF_PendingRequest *prb)
424{ 424{
425 if ((pra->public_data.type != prb->public_data.type) || 425 if ( (pra->public_data.type != prb->public_data.type) ||
426 (0 != 426 (0 != memcmp (&pra->public_data.query,
427 memcmp (&pra->public_data.query, &prb->public_data.query, 427 &prb->public_data.query,
428 sizeof (struct GNUNET_HashCode)))) 428 sizeof (struct GNUNET_HashCode))))
429 return GNUNET_NO; 429 return GNUNET_NO;
430 return GNUNET_OK; 430 return GNUNET_OK;
431} 431}
@@ -656,7 +656,8 @@ clean_request (void *cls, const struct GNUNET_HashCode *key, void *value)
656 * @param full_cleanup fully purge the request 656 * @param full_cleanup fully purge the request
657 */ 657 */
658void 658void
659GSF_pending_request_cancel_ (struct GSF_PendingRequest *pr, int full_cleanup) 659GSF_pending_request_cancel_ (struct GSF_PendingRequest *pr,
660 int full_cleanup)
660{ 661{
661 GSF_LocalLookupContinuation cont; 662 GSF_LocalLookupContinuation cont;
662 663
@@ -677,7 +678,9 @@ GSF_pending_request_cancel_ (struct GSF_PendingRequest *pr, int full_cleanup)
677 if (NULL != (cont = pr->llc_cont)) 678 if (NULL != (cont = pr->llc_cont))
678 { 679 {
679 pr->llc_cont = NULL; 680 pr->llc_cont = NULL;
680 cont (pr->llc_cont_cls, pr, pr->local_result); 681 cont (pr->llc_cont_cls,
682 pr,
683 pr->local_result);
681 } 684 }
682 GSF_plan_notify_request_done_ (pr); 685 GSF_plan_notify_request_done_ (pr);
683 if (NULL != pr->qe) 686 if (NULL != pr->qe)
@@ -698,7 +701,9 @@ GSF_pending_request_cancel_ (struct GSF_PendingRequest *pr, int full_cleanup)
698 return; 701 return;
699 } 702 }
700 GNUNET_assert (GNUNET_YES == 703 GNUNET_assert (GNUNET_YES ==
701 clean_request (NULL, &pr->public_data.query, pr)); 704 clean_request (NULL,
705 &pr->public_data.query,
706 pr));
702} 707}
703 708
704 709