diff options
author | Christian Grothoff <christian@grothoff.org> | 2015-10-25 23:04:09 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2015-10-25 23:04:09 +0000 |
commit | a7fbcf1c827ea25046c9f9e5c4e2a567eba72318 (patch) | |
tree | 0dd1e0bca0cbbb8add221a70a00b9dc7b51a124c | |
parent | a6d5893f9680dea995b1172f601adc27b2039b75 (diff) | |
download | gnunet-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.c | 156 | ||||
-rw-r--r-- | src/fs/gnunet-service-fs_pr.c | 19 |
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 | */ | ||
1187 | struct 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 | */ | ||
1223 | static int | ||
1224 | test_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 | |||
422 | GSF_pending_request_is_compatible_ (struct GSF_PendingRequest *pra, | 422 | GSF_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 | */ |
658 | void | 658 | void |
659 | GSF_pending_request_cancel_ (struct GSF_PendingRequest *pr, int full_cleanup) | 659 | GSF_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 | ||