diff options
author | Christian Grothoff <christian@grothoff.org> | 2017-01-26 21:01:23 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2017-01-26 21:01:23 +0100 |
commit | adf28e389d663529be51e41a96a867fe58f251c0 (patch) | |
tree | 429c420646790e39d350eeb984115f87ad8a20ea /src/cadet/gnunet-service-cadet-new_channel.c | |
parent | 6adc64ee122e9be37c6b83e9b745719b4d5940b8 (diff) | |
download | gnunet-adf28e389d663529be51e41a96a867fe58f251c0.tar.gz gnunet-adf28e389d663529be51e41a96a867fe58f251c0.zip |
use 'futures' bitfield in ACKs properly, revisit unbuffered/out-of-order transmission
Diffstat (limited to 'src/cadet/gnunet-service-cadet-new_channel.c')
-rw-r--r-- | src/cadet/gnunet-service-cadet-new_channel.c | 215 |
1 files changed, 135 insertions, 80 deletions
diff --git a/src/cadet/gnunet-service-cadet-new_channel.c b/src/cadet/gnunet-service-cadet-new_channel.c index a923f19dc..f5e310cfc 100644 --- a/src/cadet/gnunet-service-cadet-new_channel.c +++ b/src/cadet/gnunet-service-cadet-new_channel.c | |||
@@ -25,21 +25,16 @@ | |||
25 | * @author Christian Grothoff | 25 | * @author Christian Grothoff |
26 | * | 26 | * |
27 | * TODO: | 27 | * TODO: |
28 | * - Optimize ACKs by using 'mid_futures' properly! | 28 | * - Congestion/flow control: |
29 | * - calculate current RTT if possible, use that for initial retransmissions | 29 | * + calculate current RTT if possible, use that for initial retransmissions |
30 | * (NOTE: needs us to learn which connection the tunnel uses for the message!) | 30 | * (NOTE: needs us to learn which connection the tunnel uses for the message!) |
31 | * - introduce shutdown so we can have half-closed channels, modify | 31 | * + estimate max bandwidth using bursts and use to for CONGESTION CONTROL! |
32 | * destroy to include MID to have FIN-ACK equivalents, etc. | 32 | * (and figure out how/where to use this!) |
33 | * - estimate max bandwidth using bursts and use to for CONGESTION CONTROL! | 33 | * + figure out flow control without ACKs (unreliable traffic!) |
34 | * (and figure out how/where to use this!) | ||
35 | * - check that '0xFFULL' really is sufficient for flow control! | ||
36 | * (this is right now a big HACK!) | ||
37 | * - revisit handling of 'unreliable' traffic! | ||
38 | * (has not seen enough review) | ||
39 | * - revisit handling of 'unbuffered' traffic! | 34 | * - revisit handling of 'unbuffered' traffic! |
40 | * (has not seen enough review) | 35 | * (need to push down through tunnel into connection selection) |
41 | * - revisit handling of 'out-of-order' option, especially in combination with/without 'reliable'. | 36 | * - revisit handling of 'buffered' traffic: 4 is a rather small buffer; maybe |
42 | * - figure out flow control without ACKs (unreliable traffic!) | 37 | * reserve more bits in 'options' to allow for buffer size control? |
43 | */ | 38 | */ |
44 | #include "platform.h" | 39 | #include "platform.h" |
45 | #include "gnunet_util_lib.h" | 40 | #include "gnunet_util_lib.h" |
@@ -216,6 +211,11 @@ struct CadetChannelClient | |||
216 | struct GNUNET_CADET_ClientChannelNumber ccn; | 211 | struct GNUNET_CADET_ClientChannelNumber ccn; |
217 | 212 | ||
218 | /** | 213 | /** |
214 | * Number of entries currently in @a head_recv DLL. | ||
215 | */ | ||
216 | unsigned int num_recv; | ||
217 | |||
218 | /** | ||
219 | * Can we send data to the client? | 219 | * Can we send data to the client? |
220 | */ | 220 | */ |
221 | int client_ready; | 221 | int client_ready; |
@@ -295,8 +295,6 @@ struct CadetChannel | |||
295 | 295 | ||
296 | /** | 296 | /** |
297 | * Bitfield of already-received messages past @e mid_recv. | 297 | * Bitfield of already-received messages past @e mid_recv. |
298 | * | ||
299 | * FIXME: not yet properly used (bits here are never set!) | ||
300 | */ | 298 | */ |
301 | uint64_t mid_futures; | 299 | uint64_t mid_futures; |
302 | 300 | ||
@@ -332,6 +330,12 @@ struct CadetChannel | |||
332 | enum CadetChannelState state; | 330 | enum CadetChannelState state; |
333 | 331 | ||
334 | /** | 332 | /** |
333 | * Count how many ACKs we skipped, used to prevent long | ||
334 | * sequences of ACK skipping. | ||
335 | */ | ||
336 | unsigned int skip_ack_series; | ||
337 | |||
338 | /** | ||
335 | * Is the tunnel bufferless (minimum latency)? | 339 | * Is the tunnel bufferless (minimum latency)? |
336 | */ | 340 | */ |
337 | int nobuffer; | 341 | int nobuffer; |
@@ -416,6 +420,7 @@ free_channel_client (struct CadetChannelClient *ccc) | |||
416 | GNUNET_CONTAINER_DLL_remove (ccc->head_recv, | 420 | GNUNET_CONTAINER_DLL_remove (ccc->head_recv, |
417 | ccc->tail_recv, | 421 | ccc->tail_recv, |
418 | com); | 422 | com); |
423 | ccc->num_recv--; | ||
419 | GNUNET_MQ_discard (com->env); | 424 | GNUNET_MQ_discard (com->env); |
420 | GNUNET_free (com); | 425 | GNUNET_free (com); |
421 | } | 426 | } |
@@ -772,10 +777,12 @@ send_channel_data_ack (struct CadetChannel *ch) | |||
772 | { | 777 | { |
773 | struct GNUNET_CADET_ChannelDataAckMessage msg; | 778 | struct GNUNET_CADET_ChannelDataAckMessage msg; |
774 | 779 | ||
780 | if (GNUNET_NO == ch->reliable) | ||
781 | return; /* no ACKs */ | ||
775 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK); | 782 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK); |
776 | msg.header.size = htons (sizeof (msg)); | 783 | msg.header.size = htons (sizeof (msg)); |
777 | msg.ctn = ch->ctn; | 784 | msg.ctn = ch->ctn; |
778 | msg.mid.mid = htonl (ntohl (ch->mid_recv.mid) - 1); | 785 | msg.mid.mid = htonl (ntohl (ch->mid_recv.mid)); |
779 | msg.futures = GNUNET_htonll (ch->mid_futures); | 786 | msg.futures = GNUNET_htonll (ch->mid_futures); |
780 | if (NULL != ch->last_control_qe) | 787 | if (NULL != ch->last_control_qe) |
781 | GCT_send_cancel (ch->last_control_qe); | 788 | GCT_send_cancel (ch->last_control_qe); |
@@ -1128,6 +1135,7 @@ GCCH_handle_channel_plaintext_data (struct CadetChannel *ch, | |||
1128 | uint32_t mid_min; | 1135 | uint32_t mid_min; |
1129 | uint32_t mid_max; | 1136 | uint32_t mid_max; |
1130 | uint32_t mid_msg; | 1137 | uint32_t mid_msg; |
1138 | uint32_t delta; | ||
1131 | 1139 | ||
1132 | GNUNET_assert (GNUNET_NO == ch->is_loopback); | 1140 | GNUNET_assert (GNUNET_NO == ch->is_loopback); |
1133 | if ( (GNUNET_YES == ch->destroy) && | 1141 | if ( (GNUNET_YES == ch->destroy) && |
@@ -1140,8 +1148,9 @@ GCCH_handle_channel_plaintext_data (struct CadetChannel *ch, | |||
1140 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1148 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1141 | "Dropping incoming payload on %s as this end is already closed\n", | 1149 | "Dropping incoming payload on %s as this end is already closed\n", |
1142 | GCCH_2s (ch)); | 1150 | GCCH_2s (ch)); |
1143 | /* FIXME: send back ACK/NACK/Closed notification | 1151 | /* send back DESTROY notification to stop further retransmissions! */ |
1144 | to stop retransmissions! */ | 1152 | GCT_send_channel_destroy (ch->t, |
1153 | ch->ctn); | ||
1145 | return; | 1154 | return; |
1146 | } | 1155 | } |
1147 | payload_size = ntohs (msg->header.size) - sizeof (*msg); | 1156 | payload_size = ntohs (msg->header.size) - sizeof (*msg); |
@@ -1168,31 +1177,80 @@ GCCH_handle_channel_plaintext_data (struct CadetChannel *ch, | |||
1168 | env); | 1177 | env); |
1169 | ch->mid_recv.mid = htonl (1 + ntohl (ch->mid_recv.mid)); | 1178 | ch->mid_recv.mid = htonl (1 + ntohl (ch->mid_recv.mid)); |
1170 | ch->mid_futures >>= 1; | 1179 | ch->mid_futures >>= 1; |
1171 | if (GNUNET_YES == ch->reliable) | 1180 | send_channel_data_ack (ch); |
1172 | send_channel_data_ack (ch); | ||
1173 | return; | 1181 | return; |
1174 | } | 1182 | } |
1175 | 1183 | ||
1176 | /* check if message ought to be dropped because it is anicent/too distant/duplicate */ | 1184 | if (GNUNET_YES == ch->reliable) |
1177 | mid_min = ntohl (ch->mid_recv.mid); | ||
1178 | mid_max = mid_min + MAX_OUT_OF_ORDER_DISTANCE; | ||
1179 | mid_msg = ntohl (msg->mid.mid); | ||
1180 | if ( ( (uint32_t) (mid_msg - mid_min) > MAX_OUT_OF_ORDER_DISTANCE) || | ||
1181 | ( (uint32_t) (mid_max - mid_msg) > MAX_OUT_OF_ORDER_DISTANCE) ) | ||
1182 | { | 1185 | { |
1183 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1186 | /* check if message ought to be dropped because it is ancient/too distant/duplicate */ |
1184 | "Duplicate ancient or future payload of %u bytes on %s (mid %u) dropped\n", | 1187 | mid_min = ntohl (ch->mid_recv.mid); |
1185 | (unsigned int) payload_size, | 1188 | mid_max = mid_min + ch->max_pending_messages; |
1186 | GCCH_2s (ch), | 1189 | mid_msg = ntohl (msg->mid.mid); |
1187 | ntohl (msg->mid.mid)); | 1190 | if ( ( (uint32_t) (mid_msg - mid_min) > ch->max_pending_messages) || |
1188 | GNUNET_STATISTICS_update (stats, | 1191 | ( (uint32_t) (mid_max - mid_msg) > ch->max_pending_messages) ) |
1189 | "# duplicate DATA (ancient or future)", | 1192 | { |
1190 | 1, | 1193 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1191 | GNUNET_NO); | 1194 | "%s at %u drops ancient or far-future message %u\n", |
1192 | GNUNET_MQ_discard (env); | 1195 | GCCH_2s (ch), |
1193 | if (GNUNET_YES == ch->reliable) | 1196 | (unsigned int) mid_min, |
1197 | ntohl (msg->mid.mid)); | ||
1198 | |||
1199 | GNUNET_STATISTICS_update (stats, | ||
1200 | "# duplicate DATA (ancient or future)", | ||
1201 | 1, | ||
1202 | GNUNET_NO); | ||
1203 | GNUNET_MQ_discard (env); | ||
1194 | send_channel_data_ack (ch); | 1204 | send_channel_data_ack (ch); |
1195 | return; | 1205 | return; |
1206 | } | ||
1207 | /* mark bit for future ACKs */ | ||
1208 | delta = mid_msg - mid_min - 1; /* overflow/underflow are OK here */ | ||
1209 | if (delta < 64) | ||
1210 | { | ||
1211 | if (0 != (ch->mid_futures & (1LLU << delta))) | ||
1212 | { | ||
1213 | /* Duplicate within the queue, drop also */ | ||
1214 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1215 | "Duplicate payload of %u bytes on %s (mid %u) dropped\n", | ||
1216 | (unsigned int) payload_size, | ||
1217 | GCCH_2s (ch), | ||
1218 | ntohl (msg->mid.mid)); | ||
1219 | GNUNET_STATISTICS_update (stats, | ||
1220 | "# duplicate DATA", | ||
1221 | 1, | ||
1222 | GNUNET_NO); | ||
1223 | GNUNET_MQ_discard (env); | ||
1224 | send_channel_data_ack (ch); | ||
1225 | return; | ||
1226 | } | ||
1227 | ch->mid_futures |= (1LLU << delta); | ||
1228 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1229 | "Marked bit %llX for mid %u (base: %u); now: %llX\n", | ||
1230 | (1LLU << delta), | ||
1231 | mid_msg, | ||
1232 | mid_min, | ||
1233 | ch->mid_futures); | ||
1234 | } | ||
1235 | } | ||
1236 | else /* ! ch->reliable */ | ||
1237 | { | ||
1238 | /* Channel is unreliable, so we do not ACK. But we also cannot | ||
1239 | allow buffering everything, so check if we have space... */ | ||
1240 | if (ccc->num_recv >= ch->max_pending_messages) | ||
1241 | { | ||
1242 | struct CadetOutOfOrderMessage *drop; | ||
1243 | |||
1244 | /* Yep, need to drop. Drop the oldest message in | ||
1245 | the buffer. */ | ||
1246 | drop = ccc->head_recv; | ||
1247 | GNUNET_CONTAINER_DLL_remove (ccc->head_recv, | ||
1248 | ccc->tail_recv, | ||
1249 | drop); | ||
1250 | ccc->num_recv--; | ||
1251 | GNUNET_MQ_discard (drop->env); | ||
1252 | GNUNET_free (drop); | ||
1253 | } | ||
1196 | } | 1254 | } |
1197 | 1255 | ||
1198 | /* Insert message into sorted out-of-order queue */ | 1256 | /* Insert message into sorted out-of-order queue */ |
@@ -1206,9 +1264,14 @@ GCCH_handle_channel_plaintext_data (struct CadetChannel *ch, | |||
1206 | ccc->head_recv, | 1264 | ccc->head_recv, |
1207 | ccc->tail_recv, | 1265 | ccc->tail_recv, |
1208 | com); | 1266 | com); |
1267 | ccc->num_recv++; | ||
1209 | if (GNUNET_YES == duplicate) | 1268 | if (GNUNET_YES == duplicate) |
1210 | { | 1269 | { |
1211 | /* Duplicate within the queue, drop also */ | 1270 | /* Duplicate within the queue, drop also (this is not covered by |
1271 | the case above if "delta" >= 64, which could be the case if | ||
1272 | max_pending_messages is also >= 64 or if our client is unready | ||
1273 | and we are seeing retransmissions of the message our client is | ||
1274 | blocked on. */ | ||
1212 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1275 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1213 | "Duplicate payload of %u bytes on %s (mid %u) dropped\n", | 1276 | "Duplicate payload of %u bytes on %s (mid %u) dropped\n", |
1214 | (unsigned int) payload_size, | 1277 | (unsigned int) payload_size, |
@@ -1221,10 +1284,10 @@ GCCH_handle_channel_plaintext_data (struct CadetChannel *ch, | |||
1221 | GNUNET_CONTAINER_DLL_remove (ccc->head_recv, | 1284 | GNUNET_CONTAINER_DLL_remove (ccc->head_recv, |
1222 | ccc->tail_recv, | 1285 | ccc->tail_recv, |
1223 | com); | 1286 | com); |
1287 | ccc->num_recv--; | ||
1224 | GNUNET_MQ_discard (com->env); | 1288 | GNUNET_MQ_discard (com->env); |
1225 | GNUNET_free (com); | 1289 | GNUNET_free (com); |
1226 | if (GNUNET_YES == ch->reliable) | 1290 | send_channel_data_ack (ch); |
1227 | send_channel_data_ack (ch); | ||
1228 | return; | 1291 | return; |
1229 | } | 1292 | } |
1230 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1293 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
@@ -1238,6 +1301,10 @@ GCCH_handle_channel_plaintext_data (struct CadetChannel *ch, | |||
1238 | ccc, | 1301 | ccc, |
1239 | ntohl (msg->mid.mid), | 1302 | ntohl (msg->mid.mid), |
1240 | ntohl (ch->mid_recv.mid)); | 1303 | ntohl (ch->mid_recv.mid)); |
1304 | /* NOTE: this ACK we _could_ skip, as the packet is out-of-order and | ||
1305 | the sender may already be transmitting the previous one. Needs | ||
1306 | experimental evaluation to see if/when this ACK helps or | ||
1307 | hurts. (We might even want another option.) */ | ||
1241 | send_channel_data_ack (ch); | 1308 | send_channel_data_ack (ch); |
1242 | } | 1309 | } |
1243 | 1310 | ||
@@ -1340,6 +1407,9 @@ GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch, | |||
1340 | GNUNET_break_op (0); | 1407 | GNUNET_break_op (0); |
1341 | return; | 1408 | return; |
1342 | } | 1409 | } |
1410 | /* mid_base is the MID of the next message that the | ||
1411 | other peer expects (i.e. that is missing!), everything | ||
1412 | LOWER (but excluding mid_base itself) was received. */ | ||
1343 | mid_base = ntohl (ack->mid.mid); | 1413 | mid_base = ntohl (ack->mid.mid); |
1344 | mid_mask = GNUNET_htonll (ack->futures); | 1414 | mid_mask = GNUNET_htonll (ack->futures); |
1345 | found = GNUNET_NO; | 1415 | found = GNUNET_NO; |
@@ -1348,24 +1418,12 @@ GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch, | |||
1348 | crm = crmn) | 1418 | crm = crmn) |
1349 | { | 1419 | { |
1350 | crmn = crm->next; | 1420 | crmn = crm->next; |
1351 | if (ack->mid.mid == crm->data_message->mid.mid) | 1421 | delta = (unsigned int) (ntohl (crm->data_message->mid.mid) - mid_base); |
1352 | { | ||
1353 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1354 | "Got DATA_ACK with base %u matching message %u on %s\n", | ||
1355 | (unsigned int) mid_base, | ||
1356 | ntohl (crm->data_message->mid.mid), | ||
1357 | GCCH_2s (ch)); | ||
1358 | handle_matching_ack (ch, | ||
1359 | crm); | ||
1360 | found = GNUNET_YES; | ||
1361 | continue; | ||
1362 | } | ||
1363 | delta = (unsigned int) (ntohl (crm->data_message->mid.mid) - mid_base) - 1; | ||
1364 | if (delta >= UINT_MAX - ch->max_pending_messages) | 1422 | if (delta >= UINT_MAX - ch->max_pending_messages) |
1365 | { | 1423 | { |
1366 | /* overflow, means crm was way in the past, so this ACK counts for it. */ | 1424 | /* overflow, means crm was a bit in the past, so this ACK counts for it. */ |
1367 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1425 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1368 | "Got DATA_ACK with base %u past %u on %s\n", | 1426 | "Got DATA_ACK with base %u satisfying past message %u on %s\n", |
1369 | (unsigned int) mid_base, | 1427 | (unsigned int) mid_base, |
1370 | ntohl (crm->data_message->mid.mid), | 1428 | ntohl (crm->data_message->mid.mid), |
1371 | GCCH_2s (ch)); | 1429 | GCCH_2s (ch)); |
@@ -1374,8 +1432,14 @@ GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch, | |||
1374 | found = GNUNET_YES; | 1432 | found = GNUNET_YES; |
1375 | continue; | 1433 | continue; |
1376 | } | 1434 | } |
1435 | delta--; | ||
1377 | if (delta >= 64) | 1436 | if (delta >= 64) |
1378 | continue; | 1437 | continue; |
1438 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1439 | "Testing bit %llX for mid %u (base: %u)\n", | ||
1440 | (1LLU << delta), | ||
1441 | ntohl (crm->data_message->mid.mid), | ||
1442 | mid_base); | ||
1379 | if (0 != (mid_mask & (1LLU << delta))) | 1443 | if (0 != (mid_mask & (1LLU << delta))) |
1380 | { | 1444 | { |
1381 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1445 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
@@ -1405,7 +1469,8 @@ GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch, | |||
1405 | GNUNET_SCHEDULER_cancel (ch->retry_data_task); | 1469 | GNUNET_SCHEDULER_cancel (ch->retry_data_task); |
1406 | ch->retry_data_task = NULL; | 1470 | ch->retry_data_task = NULL; |
1407 | } | 1471 | } |
1408 | if (NULL != ch->head_sent) | 1472 | if ( (NULL != ch->head_sent) && |
1473 | (NULL == ch->head_sent->qe) ) | ||
1409 | ch->retry_data_task | 1474 | ch->retry_data_task |
1410 | = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry, | 1475 | = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry, |
1411 | &retry_transmission, | 1476 | &retry_transmission, |
@@ -1606,6 +1671,7 @@ GCCH_handle_local_data (struct CadetChannel *ch, | |||
1606 | GNUNET_CONTAINER_DLL_insert_tail (receiver->head_recv, | 1671 | GNUNET_CONTAINER_DLL_insert_tail (receiver->head_recv, |
1607 | receiver->tail_recv, | 1672 | receiver->tail_recv, |
1608 | oom); | 1673 | oom); |
1674 | receiver->num_recv++; | ||
1609 | } | 1675 | } |
1610 | return GNUNET_OK; | 1676 | return GNUNET_OK; |
1611 | } | 1677 | } |
@@ -1623,14 +1689,14 @@ GCCH_handle_local_data (struct CadetChannel *ch, | |||
1623 | GNUNET_memcpy (&crm->data_message[1], | 1689 | GNUNET_memcpy (&crm->data_message[1], |
1624 | buf, | 1690 | buf, |
1625 | buf_len); | 1691 | buf_len); |
1626 | GNUNET_CONTAINER_DLL_insert (ch->head_sent, | 1692 | GNUNET_CONTAINER_DLL_insert_tail (ch->head_sent, |
1627 | ch->tail_sent, | 1693 | ch->tail_sent, |
1628 | crm); | 1694 | crm); |
1629 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1695 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1630 | "Sending %u bytes from local client to %s with MID %u\n", | 1696 | "Sending message %u from local client to %s with %u bytes\n", |
1631 | buf_len, | 1697 | ntohl (crm->data_message->mid.mid), |
1632 | GCCH_2s (ch), | 1698 | GCCH_2s (ch), |
1633 | ntohl (crm->data_message->mid.mid)); | 1699 | buf_len); |
1634 | if (NULL != ch->retry_data_task) | 1700 | if (NULL != ch->retry_data_task) |
1635 | { | 1701 | { |
1636 | GNUNET_SCHEDULER_cancel (ch->retry_data_task); | 1702 | GNUNET_SCHEDULER_cancel (ch->retry_data_task); |
@@ -1688,6 +1754,7 @@ GCCH_handle_local_ack (struct CadetChannel *ch, | |||
1688 | GNUNET_CONTAINER_DLL_remove (ccc->head_recv, | 1754 | GNUNET_CONTAINER_DLL_remove (ccc->head_recv, |
1689 | ccc->tail_recv, | 1755 | ccc->tail_recv, |
1690 | com); | 1756 | com); |
1757 | ccc->num_recv--; | ||
1691 | GSC_send_to_client (ccc->c, | 1758 | GSC_send_to_client (ccc->c, |
1692 | com->env); | 1759 | com->env); |
1693 | /* Notify sender that we can receive more */ | 1760 | /* Notify sender that we can receive more */ |
@@ -1721,7 +1788,7 @@ GCCH_handle_local_ack (struct CadetChannel *ch, | |||
1721 | } | 1788 | } |
1722 | 1789 | ||
1723 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1790 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1724 | "Got LOCAL_ACK, passing payload message %u to %s-%X on %s\n", | 1791 | "Got LOCAL_ACK, giving payload message %u to %s-%X on %s\n", |
1725 | ntohl (com->mid.mid), | 1792 | ntohl (com->mid.mid), |
1726 | GSC_2s (ccc->c), | 1793 | GSC_2s (ccc->c), |
1727 | ntohl (ccc->ccn.channel_of_client), | 1794 | ntohl (ccc->ccn.channel_of_client), |
@@ -1731,29 +1798,17 @@ GCCH_handle_local_ack (struct CadetChannel *ch, | |||
1731 | GNUNET_CONTAINER_DLL_remove (ccc->head_recv, | 1798 | GNUNET_CONTAINER_DLL_remove (ccc->head_recv, |
1732 | ccc->tail_recv, | 1799 | ccc->tail_recv, |
1733 | com); | 1800 | com); |
1801 | ccc->num_recv--; | ||
1734 | /* FIXME: if unreliable, this is not aggressive | 1802 | /* FIXME: if unreliable, this is not aggressive |
1735 | enough, as it would be OK to have lost some! */ | 1803 | enough, as it would be OK to have lost some! */ |
1804 | |||
1736 | ch->mid_recv.mid = htonl (1 + ntohl (com->mid.mid)); | 1805 | ch->mid_recv.mid = htonl (1 + ntohl (com->mid.mid)); |
1737 | ch->mid_futures >>= 1; /* equivalent to division by 2 */ | 1806 | ch->mid_futures >>= 1; /* equivalent to division by 2 */ |
1738 | ccc->client_ready = GNUNET_NO; | 1807 | ccc->client_ready = GNUNET_NO; |
1739 | GSC_send_to_client (ccc->c, | 1808 | GSC_send_to_client (ccc->c, |
1740 | com->env); | 1809 | com->env); |
1741 | GNUNET_free (com); | 1810 | GNUNET_free (com); |
1742 | if ( (0xFFULL == (ch->mid_futures & 0xFFULL)) && | 1811 | send_channel_data_ack (ch); |
1743 | (GNUNET_YES == ch->reliable) ) | ||
1744 | { | ||
1745 | /* The next 15 messages were also already received (0xFF), this | ||
1746 | suggests that the sender may be blocked on flow control | ||
1747 | urgently waiting for an ACK from us. (As we have an inherent | ||
1748 | maximum of 64 bits, and 15 is getting too close for comfort.) | ||
1749 | So we should send one now. */ | ||
1750 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1751 | "Sender on %s likely blocked on flow-control, sending ACK now.\n", | ||
1752 | GCCH_2s (ch)); | ||
1753 | if (GNUNET_YES == ch->reliable) | ||
1754 | send_channel_data_ack (ch); | ||
1755 | } | ||
1756 | |||
1757 | if (NULL != ccc->head_recv) | 1812 | if (NULL != ccc->head_recv) |
1758 | return; | 1813 | return; |
1759 | if (GNUNET_NO == ch->destroy) | 1814 | if (GNUNET_NO == ch->destroy) |