aboutsummaryrefslogtreecommitdiff
path: root/src/cadet
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2017-01-25 18:26:27 +0100
committerChristian Grothoff <christian@grothoff.org>2017-01-25 18:26:27 +0100
commit3071beacd58c57edba1cb8b392afe6873560c676 (patch)
tree293171315c0e6328f7f700f847991f399a89fc83 /src/cadet
parent2882d2f6f37801067190c8c2e9d8d3943362490b (diff)
downloadgnunet-3071beacd58c57edba1cb8b392afe6873560c676.tar.gz
gnunet-3071beacd58c57edba1cb8b392afe6873560c676.zip
handle ancient/future duplicate payload properly
Diffstat (limited to 'src/cadet')
-rw-r--r--src/cadet/gnunet-service-cadet-new_channel.c208
1 files changed, 135 insertions, 73 deletions
diff --git a/src/cadet/gnunet-service-cadet-new_channel.c b/src/cadet/gnunet-service-cadet-new_channel.c
index c4e331304..dc3d4352c 100644
--- a/src/cadet/gnunet-service-cadet-new_channel.c
+++ b/src/cadet/gnunet-service-cadet-new_channel.c
@@ -25,8 +25,6 @@
25 * @author Christian Grothoff 25 * @author Christian Grothoff
26 * 26 *
27 * TODO: 27 * TODO:
28 * - FIXME: send ACKs back to loopback clients!
29 *
30 * - introduce shutdown so we can have half-closed channels, modify 28 * - introduce shutdown so we can have half-closed channels, modify
31 * destroy to include MID to have FIN-ACK equivalents, etc. 29 * destroy to include MID to have FIN-ACK equivalents, etc.
32 * - estimate max bandwidth using bursts and use to for CONGESTION CONTROL! 30 * - estimate max bandwidth using bursts and use to for CONGESTION CONTROL!
@@ -59,6 +57,23 @@
59 */ 57 */
60#define TIMEOUT_CLOSED_PORT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30) 58#define TIMEOUT_CLOSED_PORT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30)
61 59
60/**
61 * How long do we wait at least before retransmitting ever?
62 */
63#define MIN_RTT_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 75)
64
65/**
66 * Maximum message ID into the future we accept for out-of-order messages.
67 * If the message is more than this into the future, we drop it. This is
68 * important both to detect values that are actually in the past, as well
69 * as to limit adversarially triggerable memory consumption.
70 *
71 * Note that right now we have "max_pending_messages = 4" hard-coded in
72 * the logic below, so a value of 4 would suffice here. But we plan to
73 * allow larger windows in the future...
74 */
75#define MAX_OUT_OF_ORDER_DISTANCE 1024
76
62 77
63/** 78/**
64 * All the states a connection can be in. 79 * All the states a connection can be in.
@@ -1128,8 +1143,9 @@ GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
1128 (msg->mid.mid == ch->mid_recv.mid) ) ) 1143 (msg->mid.mid == ch->mid_recv.mid) ) )
1129 { 1144 {
1130 LOG (GNUNET_ERROR_TYPE_DEBUG, 1145 LOG (GNUNET_ERROR_TYPE_DEBUG,
1131 "Giving %u bytes of payload from %s to client %s\n", 1146 "Giving %u bytes of payload with MID %u from %s to client %s\n",
1132 (unsigned int) payload_size, 1147 (unsigned int) payload_size,
1148 ntohl (msg->mid.mid),
1133 GCCH_2s (ch), 1149 GCCH_2s (ch),
1134 GSC_2s (ccc->c)); 1150 GSC_2s (ccc->c));
1135 ccc->client_ready = GNUNET_NO; 1151 ccc->client_ready = GNUNET_NO;
@@ -1142,9 +1158,28 @@ GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
1142 { 1158 {
1143 struct CadetOutOfOrderMessage *com; 1159 struct CadetOutOfOrderMessage *com;
1144 int duplicate; 1160 int duplicate;
1145 1161 uint32_t mid_min;
1146 /* FIXME-SECURITY: if the element is WAY too far ahead, 1162 uint32_t mid_max;
1147 drop it (can't buffer too much!) */ 1163 uint32_t mid_msg;
1164
1165 mid_min = ntohl (ch->mid_recv.mid);
1166 mid_max = mid_min + MAX_OUT_OF_ORDER_DISTANCE;
1167 mid_msg = ntohl (msg->mid.mid);
1168 if ( ( (uint32_t) (mid_msg - mid_min) > MAX_OUT_OF_ORDER_DISTANCE) ||
1169 ( (uint32_t) (mid_max - mid_msg) > MAX_OUT_OF_ORDER_DISTANCE) )
1170 {
1171 LOG (GNUNET_ERROR_TYPE_DEBUG,
1172 "Duplicate ancient or future payload of %u bytes on %s (mid %u) dropped\n",
1173 (unsigned int) payload_size,
1174 GCCH_2s (ch),
1175 ntohl (msg->mid.mid));
1176 GNUNET_STATISTICS_update (stats,
1177 "# duplicate DATA (ancient or future)",
1178 1,
1179 GNUNET_NO);
1180 GNUNET_MQ_discard (env);
1181 return;
1182 }
1148 1183
1149 com = GNUNET_new (struct CadetOutOfOrderMessage); 1184 com = GNUNET_new (struct CadetOutOfOrderMessage);
1150 com->mid = msg->mid; 1185 com->mid = msg->mid;
@@ -1188,6 +1223,44 @@ GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
1188 1223
1189 1224
1190/** 1225/**
1226 * Function called once the tunnel has sent one of our messages.
1227 * If the message is unreliable, simply frees the `crm`. If the
1228 * message was reliable, calculate retransmission time and
1229 * wait for ACK (or retransmit).
1230 *
1231 * @param cls the `struct CadetReliableMessage` that was sent
1232 */
1233static void
1234data_sent_cb (void *cls);
1235
1236
1237/**
1238 * We need to retry a transmission, the last one took too long to
1239 * be acknowledged.
1240 *
1241 * @param cls the `struct CadetChannel` where we need to retransmit
1242 */
1243static void
1244retry_transmission (void *cls)
1245{
1246 struct CadetChannel *ch = cls;
1247 struct CadetReliableMessage *crm = ch->head_sent;
1248
1249 ch->retry_data_task = NULL;
1250 GNUNET_assert (NULL == crm->qe);
1251 LOG (GNUNET_ERROR_TYPE_DEBUG,
1252 "Retrying transmission on %s of message %u\n",
1253 GCCH_2s (ch),
1254 (unsigned int) ntohl (crm->data_message->mid.mid));
1255 crm->qe = GCT_send (ch->t,
1256 &crm->data_message->header,
1257 &data_sent_cb,
1258 crm);
1259 GNUNET_assert (NULL == ch->retry_data_task);
1260}
1261
1262
1263/**
1191 * We got an acknowledgement for payload data for a channel. 1264 * We got an acknowledgement for payload data for a channel.
1192 * Possibly resume transmissions. 1265 * Possibly resume transmissions.
1193 * 1266 *
@@ -1199,6 +1272,7 @@ GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
1199 const struct GNUNET_CADET_ChannelDataAckMessage *ack) 1272 const struct GNUNET_CADET_ChannelDataAckMessage *ack)
1200{ 1273{
1201 struct CadetReliableMessage *crm; 1274 struct CadetReliableMessage *crm;
1275 int was_head;
1202 1276
1203 GNUNET_break (GNUNET_NO == ch->is_loopback); 1277 GNUNET_break (GNUNET_NO == ch->is_loopback);
1204 if (GNUNET_NO == ch->reliable) 1278 if (GNUNET_NO == ch->reliable)
@@ -1225,16 +1299,13 @@ GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
1225 GNUNET_NO); 1299 GNUNET_NO);
1226 return; 1300 return;
1227 } 1301 }
1302 was_head = (crm == ch->head_sent);
1228 GNUNET_CONTAINER_DLL_remove (ch->head_sent, 1303 GNUNET_CONTAINER_DLL_remove (ch->head_sent,
1229 ch->tail_sent, 1304 ch->tail_sent,
1230 crm); 1305 crm);
1231 GNUNET_free (crm->data_message); 1306 GNUNET_free (crm->data_message);
1232 GNUNET_free (crm); 1307 GNUNET_free (crm);
1233 ch->pending_messages--; 1308 ch->pending_messages--;
1234 send_ack_to_client (ch,
1235 (NULL == ch->owner)
1236 ? GNUNET_NO
1237 : GNUNET_YES);
1238 GNUNET_assert (ch->pending_messages < ch->max_pending_messages); 1309 GNUNET_assert (ch->pending_messages < ch->max_pending_messages);
1239 LOG (GNUNET_ERROR_TYPE_DEBUG, 1310 LOG (GNUNET_ERROR_TYPE_DEBUG,
1240 "Received DATA_ACK on %s for message %u (%u ACKs pending)\n", 1311 "Received DATA_ACK on %s for message %u (%u ACKs pending)\n",
@@ -1245,6 +1316,19 @@ GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
1245 (NULL == ch->owner) 1316 (NULL == ch->owner)
1246 ? GNUNET_NO 1317 ? GNUNET_NO
1247 : GNUNET_YES); 1318 : GNUNET_YES);
1319 if (was_head)
1320 {
1321 if (NULL != ch->retry_data_task)
1322 {
1323 GNUNET_SCHEDULER_cancel (ch->retry_data_task);
1324 ch->retry_data_task = NULL;
1325 }
1326 if (NULL != ch->head_sent)
1327 ch->retry_data_task
1328 = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry,
1329 &retry_transmission,
1330 ch);
1331 }
1248} 1332}
1249 1333
1250 1334
@@ -1287,39 +1371,24 @@ GCCH_handle_remote_destroy (struct CadetChannel *ch)
1287 1371
1288 1372
1289/** 1373/**
1290 * Function called once the tunnel has sent one of our messages. 1374 * Test if element @a e1 comes before element @a e2.
1291 * If the message is unreliable, simply frees the `crm`. If the
1292 * message was reliable, calculate retransmission time and
1293 * wait for ACK (or retransmit).
1294 *
1295 * @param cls the `struct CadetReliableMessage` that was sent
1296 */
1297static void
1298data_sent_cb (void *cls);
1299
1300
1301/**
1302 * We need to retry a transmission, the last one took too long to
1303 * be acknowledged.
1304 * 1375 *
1305 * @param cls the `struct CadetChannel` where we need to retransmit 1376 * @param cls closure, to a flag where we indicate duplicate packets
1377 * @param crm1 an element of to sort
1378 * @param crm2 another element to sort
1379 * @return #GNUNET_YES if @e1 < @e2, otherwise #GNUNET_NO
1306 */ 1380 */
1307static void 1381static int
1308retry_transmission (void *cls) 1382cmp_crm_by_next_retry (void *cls,
1383 struct CadetReliableMessage *crm1,
1384 struct CadetReliableMessage *crm2)
1309{ 1385{
1310 struct CadetChannel *ch = cls; 1386 if (crm1->next_retry.abs_value_us <
1311 struct CadetReliableMessage *crm = ch->head_sent; 1387 crm2->next_retry.abs_value_us)
1312 1388 return GNUNET_YES;
1313 ch->retry_data_task = NULL; 1389 return GNUNET_NO;
1314 GNUNET_assert (NULL == crm->qe);
1315 crm->qe = GCT_send (ch->t,
1316 &crm->data_message->header,
1317 &data_sent_cb,
1318 crm);
1319 GNUNET_assert (NULL == ch->retry_data_task);
1320} 1390}
1321 1391
1322
1323/** 1392/**
1324 * Function called once the tunnel has sent one of our messages. 1393 * Function called once the tunnel has sent one of our messages.
1325 * If the message is unreliable, simply frees the `crm`. If the 1394 * If the message is unreliable, simply frees the `crm`. If the
@@ -1333,12 +1402,10 @@ data_sent_cb (void *cls)
1333{ 1402{
1334 struct CadetReliableMessage *crm = cls; 1403 struct CadetReliableMessage *crm = cls;
1335 struct CadetChannel *ch = crm->ch; 1404 struct CadetChannel *ch = crm->ch;
1336 struct CadetReliableMessage *off;
1337 1405
1338 GNUNET_assert (GNUNET_NO == ch->is_loopback); 1406 GNUNET_assert (GNUNET_NO == ch->is_loopback);
1339 GNUNET_assert (NULL != crm->qe); 1407 GNUNET_assert (NULL != crm->qe);
1340 crm->qe = NULL; 1408 crm->qe = NULL;
1341 GNUNET_assert (NULL == ch->retry_data_task);
1342 GNUNET_CONTAINER_DLL_remove (ch->head_sent, 1409 GNUNET_CONTAINER_DLL_remove (ch->head_sent,
1343 ch->tail_sent, 1410 ch->tail_sent,
1344 crm); 1411 crm);
@@ -1355,40 +1422,33 @@ data_sent_cb (void *cls)
1355 } 1422 }
1356 if (0 == crm->retry_delay.rel_value_us) 1423 if (0 == crm->retry_delay.rel_value_us)
1357 crm->retry_delay = ch->expected_delay; 1424 crm->retry_delay = ch->expected_delay;
1425 else
1426 crm->retry_delay = GNUNET_TIME_STD_BACKOFF (crm->retry_delay);
1427 crm->retry_delay = GNUNET_TIME_relative_max (crm->retry_delay,
1428 MIN_RTT_DELAY);
1358 crm->next_retry = GNUNET_TIME_relative_to_absolute (crm->retry_delay); 1429 crm->next_retry = GNUNET_TIME_relative_to_absolute (crm->retry_delay);
1359 1430
1360 /* find position for re-insertion into the DLL */ 1431 GNUNET_CONTAINER_DLL_insert_sorted (struct CadetReliableMessage,
1361 if ( (NULL == ch->head_sent) || 1432 cmp_crm_by_next_retry,
1362 (crm->next_retry.abs_value_us < ch->head_sent->next_retry.abs_value_us) ) 1433 NULL,
1363 { 1434 ch->head_sent,
1364 /* insert at HEAD, also (re)schedule retry task! */
1365 GNUNET_CONTAINER_DLL_insert (ch->head_sent,
1366 ch->tail_sent,
1367 crm);
1368 GNUNET_assert (NULL == crm->qe);
1369 ch->retry_data_task
1370 = GNUNET_SCHEDULER_add_delayed (crm->retry_delay,
1371 &retry_transmission,
1372 ch);
1373 return;
1374 }
1375 for (off = ch->head_sent; NULL != off; off = off->next)
1376 if (crm->next_retry.abs_value_us < off->next_retry.abs_value_us)
1377 break;
1378 if (NULL == off)
1379 {
1380 /* insert at tail */
1381 GNUNET_CONTAINER_DLL_insert_tail (ch->head_sent,
1382 ch->tail_sent, 1435 ch->tail_sent,
1383 crm); 1436 crm);
1384 } 1437 LOG (GNUNET_ERROR_TYPE_DEBUG,
1385 else 1438 "Message %u sent, next transmission on %s in %s\n",
1439 (unsigned int) ntohl (crm->data_message->mid.mid),
1440 GCCH_2s (ch),
1441 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (ch->head_sent->next_retry),
1442 GNUNET_YES));
1443 if (crm == ch->head_sent)
1386 { 1444 {
1387 /* insert before off */ 1445 /* We are the new head, need to reschedule retry task */
1388 GNUNET_CONTAINER_DLL_insert_after (ch->head_sent, 1446 if (NULL != ch->retry_data_task)
1389 ch->tail_sent, 1447 GNUNET_SCHEDULER_cancel (ch->retry_data_task);
1390 off->prev, 1448 ch->retry_data_task
1391 crm); 1449 = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry,
1450 &retry_transmission,
1451 ch);
1392 } 1452 }
1393} 1453}
1394 1454
@@ -1486,9 +1546,10 @@ GCCH_handle_local_data (struct CadetChannel *ch,
1486 ch->tail_sent, 1546 ch->tail_sent,
1487 crm); 1547 crm);
1488 LOG (GNUNET_ERROR_TYPE_DEBUG, 1548 LOG (GNUNET_ERROR_TYPE_DEBUG,
1489 "Sending %u bytes from local client to %s\n", 1549 "Sending %u bytes from local client to %s with MID %u\n",
1490 buf_len, 1550 buf_len,
1491 GCCH_2s (ch)); 1551 GCCH_2s (ch),
1552 ntohl (crm->data_message->mid.mid));
1492 if (NULL != ch->retry_data_task) 1553 if (NULL != ch->retry_data_task)
1493 { 1554 {
1494 GNUNET_SCHEDULER_cancel (ch->retry_data_task); 1555 GNUNET_SCHEDULER_cancel (ch->retry_data_task);
@@ -1530,9 +1591,10 @@ GCCH_handle_local_ack (struct CadetChannel *ch,
1530 if (NULL == com) 1591 if (NULL == com)
1531 { 1592 {
1532 LOG (GNUNET_ERROR_TYPE_DEBUG, 1593 LOG (GNUNET_ERROR_TYPE_DEBUG,
1533 "Got LOCAL_ACK, %s-%X ready to receive more data (but none pending)!\n", 1594 "Got LOCAL_ACK, %s-%X ready to receive more data (but none pending on %s)!\n",
1534 GSC_2s (ccc->c), 1595 GSC_2s (ccc->c),
1535 ntohl (ccc->ccn.channel_of_client)); 1596 ntohl (ccc->ccn.channel_of_client),
1597 GCCH_2s (ch));
1536 return; /* none pending */ 1598 return; /* none pending */
1537 } 1599 }
1538 if (GNUNET_YES == ch->is_loopback) 1600 if (GNUNET_YES == ch->is_loopback)