aboutsummaryrefslogtreecommitdiff
path: root/src/cadet/gnunet-service-cadet-new_channel.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2017-01-26 21:01:23 +0100
committerChristian Grothoff <christian@grothoff.org>2017-01-26 21:01:23 +0100
commitadf28e389d663529be51e41a96a867fe58f251c0 (patch)
tree429c420646790e39d350eeb984115f87ad8a20ea /src/cadet/gnunet-service-cadet-new_channel.c
parent6adc64ee122e9be37c6b83e9b745719b4d5940b8 (diff)
downloadgnunet-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.c215
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)