aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxrs <xrs@mail36.net>2017-01-25 21:17:13 +0100
committerxrs <xrs@mail36.net>2017-01-25 21:17:44 +0100
commitf477898f001e61471582b24296f6cc22cf3444ea (patch)
tree6cd0e62ada4cf89004382d3d02ce319f5bd1cbc1
parente76078deb931e473565a0d718f837d60e1b9caf8 (diff)
parenta3e5e258714ea71f204be398d1384a3cdfd11e56 (diff)
downloadgnunet-f477898f001e61471582b24296f6cc22cf3444ea.tar.gz
gnunet-f477898f001e61471582b24296f6cc22cf3444ea.zip
Merge branch 'master' of ssh://gnunet.org/gnunet
-rw-r--r--src/cadet/.gitignore1
-rw-r--r--src/cadet/cadet.conf.in2
-rw-r--r--src/cadet/gnunet-service-cadet-new.c17
-rw-r--r--src/cadet/gnunet-service-cadet-new.h5
-rw-r--r--src/cadet/gnunet-service-cadet-new_channel.c478
-rw-r--r--src/cadet/gnunet-service-cadet-new_connection.c115
-rw-r--r--src/cadet/gnunet-service-cadet-new_paths.c5
-rw-r--r--src/cadet/gnunet-service-cadet-new_tunnels.c12
-rw-r--r--src/cadet/test_cadet.c38
-rw-r--r--src/core/core_api.c2
-rw-r--r--src/include/gnunet_container_lib.h28
-rw-r--r--src/util/.gitignore1
-rw-r--r--src/util/Makefile.am6
-rw-r--r--src/util/test_container_dll.c115
14 files changed, 633 insertions, 192 deletions
diff --git a/src/cadet/.gitignore b/src/cadet/.gitignore
index 096ee06eb..154eabf3b 100644
--- a/src/cadet/.gitignore
+++ b/src/cadet/.gitignore
@@ -19,3 +19,4 @@ test_cadet_5_speed_reliable
19test_cadet_5_speed_reliable_backwards 19test_cadet_5_speed_reliable_backwards
20test_cadet_local 20test_cadet_local
21test_cadet_single 21test_cadet_single
22gnunet-service-cadet-new
diff --git a/src/cadet/cadet.conf.in b/src/cadet/cadet.conf.in
index 48fd03329..a6d762786 100644
--- a/src/cadet/cadet.conf.in
+++ b/src/cadet/cadet.conf.in
@@ -3,7 +3,7 @@ FORCESTART = YES
3AUTOSTART = @AUTOSTART@ 3AUTOSTART = @AUTOSTART@
4@JAVAPORT@PORT = 2096 4@JAVAPORT@PORT = 2096
5HOSTNAME = localhost 5HOSTNAME = localhost
6BINARY = gnunet-service-cadet 6BINARY = gnunet-service-cadet-new
7# PREFIX = valgrind --leak-check=yes 7# PREFIX = valgrind --leak-check=yes
8ACCEPT_FROM = 127.0.0.1; 8ACCEPT_FROM = 127.0.0.1;
9ACCEPT_FROM6 = ::1; 9ACCEPT_FROM6 = ::1;
diff --git a/src/cadet/gnunet-service-cadet-new.c b/src/cadet/gnunet-service-cadet-new.c
index 97489f3fd..f24c9f518 100644
--- a/src/cadet/gnunet-service-cadet-new.c
+++ b/src/cadet/gnunet-service-cadet-new.c
@@ -183,6 +183,11 @@ unsigned long long ratchet_messages;
183 */ 183 */
184struct GNUNET_TIME_Relative ratchet_time; 184struct GNUNET_TIME_Relative ratchet_time;
185 185
186/**
187 * How frequently do we send KEEPALIVE messages on idle connections?
188 */
189struct GNUNET_TIME_Relative keepalive_period;
190
186 191
187/** 192/**
188 * Send a message to a client. 193 * Send a message to a client.
@@ -1335,6 +1340,18 @@ run (void *cls,
1335 "need delay value"); 1340 "need delay value");
1336 ratchet_time = GNUNET_TIME_UNIT_HOURS; 1341 ratchet_time = GNUNET_TIME_UNIT_HOURS;
1337 } 1342 }
1343 if (GNUNET_OK !=
1344 GNUNET_CONFIGURATION_get_value_time (c,
1345 "CADET",
1346 "REFRESH_CONNECTION_TIME",
1347 &keepalive_period))
1348 {
1349 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
1350 "CADET",
1351 "REFRESH_CONNECTION_TIME",
1352 "need delay value");
1353 keepalive_period = GNUNET_TIME_UNIT_MINUTES;
1354 }
1338 1355
1339 my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c); 1356 my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c);
1340 if (NULL == my_private_key) 1357 if (NULL == my_private_key)
diff --git a/src/cadet/gnunet-service-cadet-new.h b/src/cadet/gnunet-service-cadet-new.h
index 4a76c578b..721044ac4 100644
--- a/src/cadet/gnunet-service-cadet-new.h
+++ b/src/cadet/gnunet-service-cadet-new.h
@@ -226,6 +226,11 @@ extern unsigned long long ratchet_messages;
226extern struct GNUNET_TIME_Relative ratchet_time; 226extern struct GNUNET_TIME_Relative ratchet_time;
227 227
228/** 228/**
229 * How frequently do we send KEEPALIVE messages on idle connections?
230 */
231extern struct GNUNET_TIME_Relative keepalive_period;
232
233/**
229 * Signal that shutdown is happening: prevent recovery measures. 234 * Signal that shutdown is happening: prevent recovery measures.
230 */ 235 */
231extern int shutting_down; 236extern int shutting_down;
diff --git a/src/cadet/gnunet-service-cadet-new_channel.c b/src/cadet/gnunet-service-cadet-new_channel.c
index c3d5ef194..e55a9a77d 100644
--- a/src/cadet/gnunet-service-cadet-new_channel.c
+++ b/src/cadet/gnunet-service-cadet-new_channel.c
@@ -25,13 +25,19 @@
25 * @author Christian Grothoff 25 * @author Christian Grothoff
26 * 26 *
27 * TODO: 27 * TODO:
28 * - FIXME: send ACKs back to loopback clients! 28 * - Optimize ACKs by using 'mid_futures' properly!
29 * 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 * - introduce shutdown so we can have half-closed channels, modify 31 * - introduce shutdown so we can have half-closed channels, modify
31 * destroy to include MID to have FIN-ACK equivalents, etc. 32 * destroy to include MID to have FIN-ACK equivalents, etc.
32 * - estimate max bandwidth using bursts and use to for CONGESTION CONTROL! 33 * - estimate max bandwidth using bursts and use to for CONGESTION CONTROL!
34 * (and figure out how/where to use this!)
33 * - check that '0xFFULL' really is sufficient for flow control! 35 * - check that '0xFFULL' really is sufficient for flow control!
36 * (this is right now a big HACK!)
34 * - revisit handling of 'unreliable' traffic! 37 * - revisit handling of 'unreliable' traffic!
38 * (has not seen enough review)
39 * - revisit handling of 'unbuffered' traffic!
40 * (has not seen enough review)
35 * - revisit handling of 'out-of-order' option, especially in combination with/without 'reliable'. 41 * - revisit handling of 'out-of-order' option, especially in combination with/without 'reliable'.
36 * - figure out flow control without ACKs (unreliable traffic!) 42 * - figure out flow control without ACKs (unreliable traffic!)
37 */ 43 */
@@ -59,6 +65,23 @@
59 */ 65 */
60#define TIMEOUT_CLOSED_PORT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30) 66#define TIMEOUT_CLOSED_PORT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30)
61 67
68/**
69 * How long do we wait at least before retransmitting ever?
70 */
71#define MIN_RTT_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 75)
72
73/**
74 * Maximum message ID into the future we accept for out-of-order messages.
75 * If the message is more than this into the future, we drop it. This is
76 * important both to detect values that are actually in the past, as well
77 * as to limit adversarially triggerable memory consumption.
78 *
79 * Note that right now we have "max_pending_messages = 4" hard-coded in
80 * the logic below, so a value of 4 would suffice here. But we plan to
81 * allow larger windows in the future...
82 */
83#define MAX_OUT_OF_ORDER_DISTANCE 1024
84
62 85
63/** 86/**
64 * All the states a connection can be in. 87 * All the states a connection can be in.
@@ -272,6 +295,8 @@ struct CadetChannel
272 295
273 /** 296 /**
274 * 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!)
275 */ 300 */
276 uint64_t mid_futures; 301 uint64_t mid_futures;
277 302
@@ -526,6 +551,7 @@ send_channel_open (void *cls)
526 &msgcc.header, 551 &msgcc.header,
527 &channel_open_sent_cb, 552 &channel_open_sent_cb,
528 ch); 553 ch);
554 GNUNET_assert (NULL == ch->retry_control_task);
529} 555}
530 556
531 557
@@ -753,6 +779,11 @@ send_channel_data_ack (struct CadetChannel *ch)
753 msg.futures = GNUNET_htonll (ch->mid_futures); 779 msg.futures = GNUNET_htonll (ch->mid_futures);
754 if (NULL != ch->last_control_qe) 780 if (NULL != ch->last_control_qe)
755 GCT_send_cancel (ch->last_control_qe); 781 GCT_send_cancel (ch->last_control_qe);
782 LOG (GNUNET_ERROR_TYPE_DEBUG,
783 "Sending DATA_ACK %u:%llX via %s\n",
784 (unsigned int) ntohl (msg.mid.mid),
785 (unsigned long long) ch->mid_futures,
786 GCCH_2s (ch));
756 ch->last_control_qe = GCT_send (ch->t, 787 ch->last_control_qe = GCT_send (ch->t,
757 &msg.header, 788 &msg.header,
758 &send_ack_cb, 789 &send_ack_cb,
@@ -837,9 +868,16 @@ send_ack_to_client (struct CadetChannel *ch,
837 struct GNUNET_CADET_LocalAck *ack; 868 struct GNUNET_CADET_LocalAck *ack;
838 struct CadetChannelClient *ccc; 869 struct CadetChannelClient *ccc;
839 870
871 ccc = (GNUNET_YES == to_owner) ? ch->owner : ch->dest;
872 if (NULL == ccc)
873 {
874 /* This can happen if we are just getting ACKs after
875 our local client already disconnected. */
876 GNUNET_assert (GNUNET_YES == ch->destroy);
877 return;
878 }
840 env = GNUNET_MQ_msg (ack, 879 env = GNUNET_MQ_msg (ack,
841 GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK); 880 GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK);
842 ccc = (GNUNET_YES == to_owner) ? ch->owner : ch->dest;
843 ack->ccn = ccc->ccn; 881 ack->ccn = ccc->ccn;
844 LOG (GNUNET_ERROR_TYPE_DEBUG, 882 LOG (GNUNET_ERROR_TYPE_DEBUG,
845 "Sending CADET_LOCAL_ACK to %s (%s) at ccn %X (%u/%u pending)\n", 883 "Sending CADET_LOCAL_ACK to %s (%s) at ccn %X (%u/%u pending)\n",
@@ -1060,23 +1098,11 @@ is_before (void *cls,
1060 if (delta > (uint32_t) INT_MAX) 1098 if (delta > (uint32_t) INT_MAX)
1061 { 1099 {
1062 /* in overflow range, we can safely assume we wrapped around */ 1100 /* in overflow range, we can safely assume we wrapped around */
1063 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1064 "%u > %u => %p > %p\n",
1065 (unsigned int) v1,
1066 (unsigned int) v2,
1067 m1,
1068 m2);
1069 return GNUNET_NO; 1101 return GNUNET_NO;
1070 } 1102 }
1071 else 1103 else
1072 { 1104 {
1073 /* result is small, thus v2 > v1, thus e1 < e2 */ 1105 /* result is small, thus v2 > v1, thus e1 < e2 */
1074 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1075 "%u < %u => %p < %p\n",
1076 (unsigned int) v1,
1077 (unsigned int) v2,
1078 m1,
1079 m2);
1080 return GNUNET_YES; 1106 return GNUNET_YES;
1081 } 1107 }
1082} 1108}
@@ -1097,6 +1123,11 @@ GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
1097 struct GNUNET_CADET_LocalData *ld; 1123 struct GNUNET_CADET_LocalData *ld;
1098 struct CadetChannelClient *ccc; 1124 struct CadetChannelClient *ccc;
1099 size_t payload_size; 1125 size_t payload_size;
1126 struct CadetOutOfOrderMessage *com;
1127 int duplicate;
1128 uint32_t mid_min;
1129 uint32_t mid_max;
1130 uint32_t mid_msg;
1100 1131
1101 GNUNET_assert (GNUNET_NO == ch->is_loopback); 1132 GNUNET_assert (GNUNET_NO == ch->is_loopback);
1102 if ( (GNUNET_YES == ch->destroy) && 1133 if ( (GNUNET_YES == ch->destroy) &&
@@ -1127,8 +1158,9 @@ GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
1127 (msg->mid.mid == ch->mid_recv.mid) ) ) 1158 (msg->mid.mid == ch->mid_recv.mid) ) )
1128 { 1159 {
1129 LOG (GNUNET_ERROR_TYPE_DEBUG, 1160 LOG (GNUNET_ERROR_TYPE_DEBUG,
1130 "Giving %u bytes of payload from %s to client %s\n", 1161 "Giving %u bytes of payload with MID %u from %s to client %s\n",
1131 (unsigned int) payload_size, 1162 (unsigned int) payload_size,
1163 ntohl (msg->mid.mid),
1132 GCCH_2s (ch), 1164 GCCH_2s (ch),
1133 GSC_2s (ccc->c)); 1165 GSC_2s (ccc->c));
1134 ccc->client_ready = GNUNET_NO; 1166 ccc->client_ready = GNUNET_NO;
@@ -1136,52 +1168,148 @@ GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
1136 env); 1168 env);
1137 ch->mid_recv.mid = htonl (1 + ntohl (ch->mid_recv.mid)); 1169 ch->mid_recv.mid = htonl (1 + ntohl (ch->mid_recv.mid));
1138 ch->mid_futures >>= 1; 1170 ch->mid_futures >>= 1;
1171 if (GNUNET_YES == ch->reliable)
1172 send_channel_data_ack (ch);
1173 return;
1139 } 1174 }
1140 else 1175
1176 /* check if message ought to be dropped because it is anicent/too distant/duplicate */
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) )
1141 { 1182 {
1142 struct CadetOutOfOrderMessage *com;
1143 int duplicate;
1144
1145 /* FIXME-SECURITY: if the element is WAY too far ahead,
1146 drop it (can't buffer too much!) */
1147
1148 com = GNUNET_new (struct CadetOutOfOrderMessage);
1149 com->mid = msg->mid;
1150 com->env = env;
1151 duplicate = GNUNET_NO;
1152 GNUNET_CONTAINER_DLL_insert_sorted (struct CadetOutOfOrderMessage,
1153 is_before,
1154 &duplicate,
1155 ccc->head_recv,
1156 ccc->tail_recv,
1157 com);
1158 if (GNUNET_YES == duplicate)
1159 {
1160 LOG (GNUNET_ERROR_TYPE_DEBUG,
1161 "Duplicate payload of %u bytes on %s (mid %u) dropped\n",
1162 (unsigned int) payload_size,
1163 GCCH_2s (ch),
1164 ntohl (msg->mid.mid));
1165 GNUNET_STATISTICS_update (stats,
1166 "# duplicate DATA",
1167 1,
1168 GNUNET_NO);
1169 GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
1170 ccc->tail_recv,
1171 com);
1172 GNUNET_free (com);
1173 return;
1174 }
1175 LOG (GNUNET_ERROR_TYPE_DEBUG, 1183 LOG (GNUNET_ERROR_TYPE_DEBUG,
1176 "Queued %s payload of %u bytes on %s (mid %u, need %u first)\n", 1184 "Duplicate ancient or future payload of %u bytes on %s (mid %u) dropped\n",
1177 (GNUNET_YES == ccc->client_ready)
1178 ? "out-of-order"
1179 : "client-not-ready",
1180 (unsigned int) payload_size, 1185 (unsigned int) payload_size,
1181 GCCH_2s (ch), 1186 GCCH_2s (ch),
1182 ntohl (msg->mid.mid), 1187 ntohl (msg->mid.mid));
1183 ntohl (ch->mid_recv.mid)); 1188 GNUNET_STATISTICS_update (stats,
1189 "# duplicate DATA (ancient or future)",
1190 1,
1191 GNUNET_NO);
1192 GNUNET_MQ_discard (env);
1193 return;
1194 }
1195
1196 /* Insert message into sorted out-of-order queue */
1197 com = GNUNET_new (struct CadetOutOfOrderMessage);
1198 com->mid = msg->mid;
1199 com->env = env;
1200 duplicate = GNUNET_NO;
1201 GNUNET_CONTAINER_DLL_insert_sorted (struct CadetOutOfOrderMessage,
1202 is_before,
1203 &duplicate,
1204 ccc->head_recv,
1205 ccc->tail_recv,
1206 com);
1207 if (GNUNET_YES == duplicate)
1208 {
1209 /* Duplicate within the queue, drop also */
1210 LOG (GNUNET_ERROR_TYPE_DEBUG,
1211 "Duplicate payload of %u bytes on %s (mid %u) dropped\n",
1212 (unsigned int) payload_size,
1213 GCCH_2s (ch),
1214 ntohl (msg->mid.mid));
1215 GNUNET_STATISTICS_update (stats,
1216 "# duplicate DATA",
1217 1,
1218 GNUNET_NO);
1219 GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
1220 ccc->tail_recv,
1221 com);
1222 GNUNET_MQ_discard (com->env);
1223 GNUNET_free (com);
1224 if (GNUNET_YES == ch->reliable)
1225 send_channel_data_ack (ch);
1226 return;
1184 } 1227 }
1228 LOG (GNUNET_ERROR_TYPE_DEBUG,
1229 "Queued %s payload of %u bytes on %s-%X(%p) (mid %u, need %u first)\n",
1230 (GNUNET_YES == ccc->client_ready)
1231 ? "out-of-order"
1232 : "client-not-ready",
1233 (unsigned int) payload_size,
1234 GCCH_2s (ch),
1235 ntohl (ccc->ccn.channel_of_client),
1236 ccc,
1237 ntohl (msg->mid.mid),
1238 ntohl (ch->mid_recv.mid));
1239 send_channel_data_ack (ch);
1240}
1241
1242
1243/**
1244 * Function called once the tunnel has sent one of our messages.
1245 * If the message is unreliable, simply frees the `crm`. If the
1246 * message was reliable, calculate retransmission time and
1247 * wait for ACK (or retransmit).
1248 *
1249 * @param cls the `struct CadetReliableMessage` that was sent
1250 */
1251static void
1252data_sent_cb (void *cls);
1253
1254
1255/**
1256 * We need to retry a transmission, the last one took too long to
1257 * be acknowledged.
1258 *
1259 * @param cls the `struct CadetChannel` where we need to retransmit
1260 */
1261static void
1262retry_transmission (void *cls)
1263{
1264 struct CadetChannel *ch = cls;
1265 struct CadetReliableMessage *crm = ch->head_sent;
1266
1267 ch->retry_data_task = NULL;
1268 GNUNET_assert (NULL == crm->qe);
1269 LOG (GNUNET_ERROR_TYPE_DEBUG,
1270 "Retrying transmission on %s of message %u\n",
1271 GCCH_2s (ch),
1272 (unsigned int) ntohl (crm->data_message->mid.mid));
1273 crm->qe = GCT_send (ch->t,
1274 &crm->data_message->header,
1275 &data_sent_cb,
1276 crm);
1277 GNUNET_assert (NULL == ch->retry_data_task);
1278}
1279
1280
1281/**
1282 * We got an PLAINTEXT_DATA_ACK for a message in our queue, remove it from
1283 * the queue and tell our client that it can send more.
1284 *
1285 * @param ch the channel that got the PLAINTEXT_DATA_ACK
1286 * @param crm the message that got acknowledged
1287 */
1288static void
1289handle_matching_ack (struct CadetChannel *ch,
1290 struct CadetReliableMessage *crm)
1291{
1292 GNUNET_CONTAINER_DLL_remove (ch->head_sent,
1293 ch->tail_sent,
1294 crm);
1295 ch->pending_messages--;
1296 GNUNET_assert (ch->pending_messages < ch->max_pending_messages);
1297 LOG (GNUNET_ERROR_TYPE_DEBUG,
1298 "Received DATA_ACK on %s for message %u (%u ACKs pending)\n",
1299 GCCH_2s (ch),
1300 (unsigned int) ntohl (crm->data_message->mid.mid),
1301 ch->pending_messages);
1302 if (NULL != crm->qe)
1303 {
1304 GCT_send_cancel (crm->qe);
1305 crm->qe = NULL;
1306 }
1307 GNUNET_free (crm->data_message);
1308 GNUNET_free (crm);
1309 send_ack_to_client (ch,
1310 (NULL == ch->owner)
1311 ? GNUNET_NO
1312 : GNUNET_YES);
1185} 1313}
1186 1314
1187 1315
@@ -1197,6 +1325,11 @@ GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
1197 const struct GNUNET_CADET_ChannelDataAckMessage *ack) 1325 const struct GNUNET_CADET_ChannelDataAckMessage *ack)
1198{ 1326{
1199 struct CadetReliableMessage *crm; 1327 struct CadetReliableMessage *crm;
1328 struct CadetReliableMessage *crmn;
1329 int found;
1330 uint32_t mid_base;
1331 uint64_t mid_mask;
1332 unsigned int delta;
1200 1333
1201 GNUNET_break (GNUNET_NO == ch->is_loopback); 1334 GNUNET_break (GNUNET_NO == ch->is_loopback);
1202 if (GNUNET_NO == ch->reliable) 1335 if (GNUNET_NO == ch->reliable)
@@ -1205,12 +1338,32 @@ GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
1205 GNUNET_break_op (0); 1338 GNUNET_break_op (0);
1206 return; 1339 return;
1207 } 1340 }
1341 mid_base = ntohl (ack->mid.mid);
1342 mid_mask = GNUNET_htonll (ack->futures);
1343 found = GNUNET_NO;
1208 for (crm = ch->head_sent; 1344 for (crm = ch->head_sent;
1209 NULL != crm; 1345 NULL != crm;
1210 crm = crm->next) 1346 crm = crmn)
1347 {
1348 crmn = crm->next;
1211 if (ack->mid.mid == crm->data_message->mid.mid) 1349 if (ack->mid.mid == crm->data_message->mid.mid)
1212 break; 1350 {
1213 if (NULL == crm) 1351 handle_matching_ack (ch,
1352 crm);
1353 found = GNUNET_YES;
1354 continue;
1355 }
1356 delta = (unsigned int) (ntohl (crm->data_message->mid.mid) - mid_base) - 1;
1357 if (delta >= 64)
1358 continue;
1359 if (0 != (mid_mask & (1LLU << delta)))
1360 {
1361 handle_matching_ack (ch,
1362 crm);
1363 found = GNUNET_YES;
1364 }
1365 }
1366 if (GNUNET_NO == found)
1214 { 1367 {
1215 /* ACK for message we already dropped, might have been a 1368 /* ACK for message we already dropped, might have been a
1216 duplicate ACK? Ignore. */ 1369 duplicate ACK? Ignore. */
@@ -1223,26 +1376,16 @@ GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
1223 GNUNET_NO); 1376 GNUNET_NO);
1224 return; 1377 return;
1225 } 1378 }
1226 GNUNET_CONTAINER_DLL_remove (ch->head_sent, 1379 if (NULL != ch->retry_data_task)
1227 ch->tail_sent, 1380 {
1228 crm); 1381 GNUNET_SCHEDULER_cancel (ch->retry_data_task);
1229 GNUNET_free (crm->data_message); 1382 ch->retry_data_task = NULL;
1230 GNUNET_free (crm); 1383 }
1231 ch->pending_messages--; 1384 if (NULL != ch->head_sent)
1232 send_ack_to_client (ch, 1385 ch->retry_data_task
1233 (NULL == ch->owner) 1386 = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry,
1234 ? GNUNET_NO 1387 &retry_transmission,
1235 : GNUNET_YES); 1388 ch);
1236 GNUNET_assert (ch->pending_messages < ch->max_pending_messages);
1237 LOG (GNUNET_ERROR_TYPE_DEBUG,
1238 "Received DATA_ACK on %s for message %u (%u ACKs pending)\n",
1239 GCCH_2s (ch),
1240 (unsigned int) ntohl (ack->mid.mid),
1241 ch->pending_messages);
1242 send_ack_to_client (ch,
1243 (NULL == ch->owner)
1244 ? GNUNET_NO
1245 : GNUNET_YES);
1246} 1389}
1247 1390
1248 1391
@@ -1285,35 +1428,22 @@ GCCH_handle_remote_destroy (struct CadetChannel *ch)
1285 1428
1286 1429
1287/** 1430/**
1288 * Function called once the tunnel has sent one of our messages. 1431 * Test if element @a e1 comes before element @a e2.
1289 * If the message is unreliable, simply frees the `crm`. If the
1290 * message was reliable, calculate retransmission time and
1291 * wait for ACK (or retransmit).
1292 *
1293 * @param cls the `struct CadetReliableMessage` that was sent
1294 */
1295static void
1296data_sent_cb (void *cls);
1297
1298
1299/**
1300 * We need to retry a transmission, the last one took too long to
1301 * be acknowledged.
1302 * 1432 *
1303 * @param cls the `struct CadetChannel` where we need to retransmit 1433 * @param cls closure, to a flag where we indicate duplicate packets
1434 * @param crm1 an element of to sort
1435 * @param crm2 another element to sort
1436 * @return #GNUNET_YES if @e1 < @e2, otherwise #GNUNET_NO
1304 */ 1437 */
1305static void 1438static int
1306retry_transmission (void *cls) 1439cmp_crm_by_next_retry (void *cls,
1440 struct CadetReliableMessage *crm1,
1441 struct CadetReliableMessage *crm2)
1307{ 1442{
1308 struct CadetChannel *ch = cls; 1443 if (crm1->next_retry.abs_value_us <
1309 struct CadetReliableMessage *crm = ch->head_sent; 1444 crm2->next_retry.abs_value_us)
1310 1445 return GNUNET_YES;
1311 ch->retry_data_task = NULL; 1446 return GNUNET_NO;
1312 GNUNET_assert (NULL == crm->qe);
1313 crm->qe = GCT_send (ch->t,
1314 &crm->data_message->header,
1315 &data_sent_cb,
1316 crm);
1317} 1447}
1318 1448
1319 1449
@@ -1330,9 +1460,9 @@ data_sent_cb (void *cls)
1330{ 1460{
1331 struct CadetReliableMessage *crm = cls; 1461 struct CadetReliableMessage *crm = cls;
1332 struct CadetChannel *ch = crm->ch; 1462 struct CadetChannel *ch = crm->ch;
1333 struct CadetReliableMessage *off;
1334 1463
1335 GNUNET_assert (GNUNET_NO == ch->is_loopback); 1464 GNUNET_assert (GNUNET_NO == ch->is_loopback);
1465 GNUNET_assert (NULL != crm->qe);
1336 crm->qe = NULL; 1466 crm->qe = NULL;
1337 GNUNET_CONTAINER_DLL_remove (ch->head_sent, 1467 GNUNET_CONTAINER_DLL_remove (ch->head_sent,
1338 ch->tail_sent, 1468 ch->tail_sent,
@@ -1350,42 +1480,33 @@ data_sent_cb (void *cls)
1350 } 1480 }
1351 if (0 == crm->retry_delay.rel_value_us) 1481 if (0 == crm->retry_delay.rel_value_us)
1352 crm->retry_delay = ch->expected_delay; 1482 crm->retry_delay = ch->expected_delay;
1483 else
1484 crm->retry_delay = GNUNET_TIME_STD_BACKOFF (crm->retry_delay);
1485 crm->retry_delay = GNUNET_TIME_relative_max (crm->retry_delay,
1486 MIN_RTT_DELAY);
1353 crm->next_retry = GNUNET_TIME_relative_to_absolute (crm->retry_delay); 1487 crm->next_retry = GNUNET_TIME_relative_to_absolute (crm->retry_delay);
1354 1488
1355 /* find position for re-insertion into the DLL */ 1489 GNUNET_CONTAINER_DLL_insert_sorted (struct CadetReliableMessage,
1356 if ( (NULL == ch->head_sent) || 1490 cmp_crm_by_next_retry,
1357 (crm->next_retry.abs_value_us < ch->head_sent->next_retry.abs_value_us) ) 1491 NULL,
1492 ch->head_sent,
1493 ch->tail_sent,
1494 crm);
1495 LOG (GNUNET_ERROR_TYPE_DEBUG,
1496 "Message %u sent, next transmission on %s in %s\n",
1497 (unsigned int) ntohl (crm->data_message->mid.mid),
1498 GCCH_2s (ch),
1499 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (ch->head_sent->next_retry),
1500 GNUNET_YES));
1501 if (crm == ch->head_sent)
1358 { 1502 {
1359 /* insert at HEAD, also (re)schedule retry task! */ 1503 /* We are the new head, need to reschedule retry task */
1360 GNUNET_CONTAINER_DLL_insert (ch->head_sent,
1361 ch->tail_sent,
1362 crm);
1363 if (NULL != ch->retry_data_task) 1504 if (NULL != ch->retry_data_task)
1364 GNUNET_SCHEDULER_cancel (ch->retry_data_task); 1505 GNUNET_SCHEDULER_cancel (ch->retry_data_task);
1365 GNUNET_assert (NULL == crm->qe);
1366 ch->retry_data_task 1506 ch->retry_data_task
1367 = GNUNET_SCHEDULER_add_delayed (crm->retry_delay, 1507 = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry,
1368 &retry_transmission, 1508 &retry_transmission,
1369 ch); 1509 ch);
1370 return;
1371 }
1372 for (off = ch->head_sent; NULL != off; off = off->next)
1373 if (crm->next_retry.abs_value_us < off->next_retry.abs_value_us)
1374 break;
1375 if (NULL == off)
1376 {
1377 /* insert at tail */
1378 GNUNET_CONTAINER_DLL_insert_tail (ch->head_sent,
1379 ch->tail_sent,
1380 crm);
1381 }
1382 else
1383 {
1384 /* insert before off */
1385 GNUNET_CONTAINER_DLL_insert_after (ch->head_sent,
1386 ch->tail_sent,
1387 off->prev,
1388 crm);
1389 } 1510 }
1390} 1511}
1391 1512
@@ -1446,11 +1567,23 @@ GCCH_handle_local_data (struct CadetChannel *ch,
1446 GNUNET_memcpy (&ld[1], 1567 GNUNET_memcpy (&ld[1],
1447 buf, 1568 buf,
1448 buf_len); 1569 buf_len);
1449 /* FIXME: this does not provide for flow control! */ 1570 if (GNUNET_YES == receiver->client_ready)
1450 GSC_send_to_client (receiver->c, 1571 {
1451 env); 1572 GSC_send_to_client (receiver->c,
1452 send_ack_to_client (ch, 1573 env);
1453 to_owner); 1574 send_ack_to_client (ch,
1575 to_owner);
1576 }
1577 else
1578 {
1579 struct CadetOutOfOrderMessage *oom;
1580
1581 oom = GNUNET_new (struct CadetOutOfOrderMessage);
1582 oom->env = env;
1583 GNUNET_CONTAINER_DLL_insert_tail (receiver->head_recv,
1584 receiver->tail_recv,
1585 oom);
1586 }
1454 return GNUNET_OK; 1587 return GNUNET_OK;
1455 } 1588 }
1456 1589
@@ -1471,13 +1604,20 @@ GCCH_handle_local_data (struct CadetChannel *ch,
1471 ch->tail_sent, 1604 ch->tail_sent,
1472 crm); 1605 crm);
1473 LOG (GNUNET_ERROR_TYPE_DEBUG, 1606 LOG (GNUNET_ERROR_TYPE_DEBUG,
1474 "Sending %u bytes from local client to %s\n", 1607 "Sending %u bytes from local client to %s with MID %u\n",
1475 buf_len, 1608 buf_len,
1476 GCCH_2s (ch)); 1609 GCCH_2s (ch),
1610 ntohl (crm->data_message->mid.mid));
1611 if (NULL != ch->retry_data_task)
1612 {
1613 GNUNET_SCHEDULER_cancel (ch->retry_data_task);
1614 ch->retry_data_task = NULL;
1615 }
1477 crm->qe = GCT_send (ch->t, 1616 crm->qe = GCT_send (ch->t,
1478 &crm->data_message->header, 1617 &crm->data_message->header,
1479 &data_sent_cb, 1618 &data_sent_cb,
1480 crm); 1619 crm);
1620 GNUNET_assert (NULL == ch->retry_data_task);
1481 return GNUNET_OK; 1621 return GNUNET_OK;
1482} 1622}
1483 1623
@@ -1509,11 +1649,42 @@ GCCH_handle_local_ack (struct CadetChannel *ch,
1509 if (NULL == com) 1649 if (NULL == com)
1510 { 1650 {
1511 LOG (GNUNET_ERROR_TYPE_DEBUG, 1651 LOG (GNUNET_ERROR_TYPE_DEBUG,
1512 "Got LOCAL_ACK, %s-%X ready to receive more data (but none pending)!\n", 1652 "Got LOCAL_ACK, %s-%X ready to receive more data, but none pending on %s-%X(%p)!\n",
1513 GSC_2s (ccc->c), 1653 GSC_2s (ccc->c),
1514 ntohl (ccc->ccn.channel_of_client)); 1654 ntohl (client_ccn.channel_of_client),
1655 GCCH_2s (ch),
1656 ntohl (ccc->ccn.channel_of_client),
1657 ccc);
1515 return; /* none pending */ 1658 return; /* none pending */
1516 } 1659 }
1660 if (GNUNET_YES == ch->is_loopback)
1661 {
1662 int to_owner;
1663
1664 /* Messages are always in-order, just send */
1665 GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
1666 ccc->tail_recv,
1667 com);
1668 GSC_send_to_client (ccc->c,
1669 com->env);
1670 /* Notify sender that we can receive more */
1671 if (ccc->ccn.channel_of_client ==
1672 ch->owner->ccn.channel_of_client)
1673 {
1674 to_owner = GNUNET_NO;
1675 }
1676 else
1677 {
1678 GNUNET_assert (ccc->ccn.channel_of_client ==
1679 ch->dest->ccn.channel_of_client);
1680 to_owner = GNUNET_YES;
1681 }
1682 send_ack_to_client (ch,
1683 to_owner);
1684 GNUNET_free (com);
1685 return;
1686 }
1687
1517 if ( (com->mid.mid != ch->mid_recv.mid) && 1688 if ( (com->mid.mid != ch->mid_recv.mid) &&
1518 (GNUNET_NO == ch->out_of_order) ) 1689 (GNUNET_NO == ch->out_of_order) )
1519 { 1690 {
@@ -1526,11 +1697,12 @@ GCCH_handle_local_ack (struct CadetChannel *ch,
1526 return; /* missing next one in-order */ 1697 return; /* missing next one in-order */
1527 } 1698 }
1528 1699
1529 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1700 LOG (GNUNET_ERROR_TYPE_DEBUG,
1530 "Got LOCAL ACK, passing payload message to %s-%X on %s\n", 1701 "Got LOCAL ACK, passing payload message %u to %s-%X on %s\n",
1531 GSC_2s (ccc->c), 1702 ntohl (com->mid.mid),
1532 ntohl (ccc->ccn.channel_of_client), 1703 GSC_2s (ccc->c),
1533 GCCH_2s (ch)); 1704 ntohl (ccc->ccn.channel_of_client),
1705 GCCH_2s (ch));
1534 1706
1535 /* all good, pass next message to client */ 1707 /* all good, pass next message to client */
1536 GNUNET_CONTAINER_DLL_remove (ccc->head_recv, 1708 GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
@@ -1552,9 +1724,9 @@ GCCH_handle_local_ack (struct CadetChannel *ch,
1552 urgently waiting for an ACK from us. (As we have an inherent 1724 urgently waiting for an ACK from us. (As we have an inherent
1553 maximum of 64 bits, and 15 is getting too close for comfort.) 1725 maximum of 64 bits, and 15 is getting too close for comfort.)
1554 So we should send one now. */ 1726 So we should send one now. */
1555 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1727 LOG (GNUNET_ERROR_TYPE_DEBUG,
1556 "Sender on %s likely blocked on flow-control, sending ACK now.\n", 1728 "Sender on %s likely blocked on flow-control, sending ACK now.\n",
1557 GCCH_2s (ch)); 1729 GCCH_2s (ch));
1558 if (GNUNET_YES == ch->reliable) 1730 if (GNUNET_YES == ch->reliable)
1559 send_channel_data_ack (ch); 1731 send_channel_data_ack (ch);
1560 } 1732 }
diff --git a/src/cadet/gnunet-service-cadet-new_connection.c b/src/cadet/gnunet-service-cadet-new_connection.c
index 60389008c..58922bc1e 100644
--- a/src/cadet/gnunet-service-cadet-new_connection.c
+++ b/src/cadet/gnunet-service-cadet-new_connection.c
@@ -27,16 +27,18 @@
27 * @author Christian Grothoff 27 * @author Christian Grothoff
28 * 28 *
29 * TODO: 29 * TODO:
30 * - Optimization: keepalive messages / timeout (timeout to be done @ peer level!) 30 * - Implement: keepalive messages / timeout (timeout to be done @ peer level!)
31 * - Optimization: keep performance metrics (?) 31 * - Optimization: keep performance metrics (?)
32 */ 32 */
33#include "platform.h" 33#include "platform.h"
34#include "gnunet-service-cadet-new.h"
34#include "gnunet-service-cadet-new_channel.h" 35#include "gnunet-service-cadet-new_channel.h"
35#include "gnunet-service-cadet-new_connection.h" 36#include "gnunet-service-cadet-new_connection.h"
36#include "gnunet-service-cadet-new_paths.h" 37#include "gnunet-service-cadet-new_paths.h"
37#include "gnunet-service-cadet-new_peer.h" 38#include "gnunet-service-cadet-new_peer.h"
38#include "gnunet-service-cadet-new_tunnels.h" 39#include "gnunet-service-cadet-new_tunnels.h"
39#include "gnunet_cadet_service.h" 40#include "gnunet_cadet_service.h"
41#include "gnunet_statistics_service.h"
40#include "cadet_protocol.h" 42#include "cadet_protocol.h"
41 43
42 44
@@ -119,6 +121,11 @@ struct CadetConnection
119 struct GNUNET_SCHEDULER_Task *task; 121 struct GNUNET_SCHEDULER_Task *task;
120 122
121 /** 123 /**
124 * Queue entry for keepalive messages.
125 */
126 struct CadetTunnelQueueEntry *keepalive_qe;
127
128 /**
122 * Function to call once we are ready to transmit. 129 * Function to call once we are ready to transmit.
123 */ 130 */
124 GCC_ReadyCallback ready_cb; 131 GCC_ReadyCallback ready_cb;
@@ -184,6 +191,11 @@ GCC_destroy (struct CadetConnection *cc)
184 GNUNET_SCHEDULER_cancel (cc->task); 191 GNUNET_SCHEDULER_cancel (cc->task);
185 cc->task = NULL; 192 cc->task = NULL;
186 } 193 }
194 if (NULL != cc->keepalive_qe)
195 {
196 GCT_send_cancel (cc->keepalive_qe);
197 cc->keepalive_qe = NULL;
198 }
187 GCPP_del_connection (cc->path, 199 GCPP_del_connection (cc->path,
188 cc->off, 200 cc->off,
189 cc); 201 cc);
@@ -209,7 +221,72 @@ GCC_get_ct (struct CadetConnection *cc)
209 221
210 222
211/** 223/**
212 * A CADET_CONNECTION_ACK was received for this connection, implying 224 * Send a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE through the
225 * tunnel to prevent it from timing out.
226 *
227 * @param cls the `struct CadetConnection` to keep alive.
228 */
229static void
230send_keepalive (void *cls);
231
232
233/**
234 * Keepalive was transmitted. Remember this, and possibly
235 * schedule the next one.
236 *
237 * @param cls the `struct CadetConnection` to keep alive.
238 */
239static void
240keepalive_done (void *cls)
241{
242 struct CadetConnection *cc = cls;
243
244 cc->keepalive_qe = NULL;
245 if ( (GNUNET_YES == cc->mqm_ready) &&
246 (NULL == cc->task) )
247 cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
248 &send_keepalive,
249 cc);
250}
251
252
253/**
254 * Send a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE through the
255 * tunnel to prevent it from timing out.
256 *
257 * @param cls the `struct CadetConnection` to keep alive.
258 */
259static void
260send_keepalive (void *cls)
261{
262 struct CadetConnection *cc = cls;
263 struct GNUNET_MessageHeader msg;
264
265 cc->task = NULL;
266 GNUNET_assert (NULL != cc->ct);
267 GNUNET_assert (GNUNET_YES == cc->mqm_ready);
268 GNUNET_assert (NULL == cc->keepalive_qe);
269 LOG (GNUNET_ERROR_TYPE_INFO,
270 "Sending KEEPALIVE on behalf of %s via %s\n",
271 GCC_2s (cc),
272 GCT_2s (cc->ct->t));
273 GNUNET_STATISTICS_update (stats,
274 "# keepalives sent",
275 1,
276 GNUNET_NO);
277 msg.size = htons (sizeof (msg));
278 msg.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE);
279
280 cc->keepalive_qe
281 = GCT_send (cc->ct->t,
282 &msg,
283 &keepalive_done,
284 cc);
285}
286
287
288/**
289 * A #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK was received for this connection, implying
213 * that the end-to-end connection is up. Process it. 290 * that the end-to-end connection is up. Process it.
214 * 291 *
215 * @param cc the connection that got the ACK. 292 * @param cc the connection that got the ACK.
@@ -227,15 +304,18 @@ GCC_handle_connection_create_ack (struct CadetConnection *cc)
227 GNUNET_SCHEDULER_cancel (cc->task); 304 GNUNET_SCHEDULER_cancel (cc->task);
228 cc->task = NULL; 305 cc->task = NULL;
229 } 306 }
230#if FIXME_KEEPALIVE
231 cc->task = GNUNET_SCHEDULER_add_delayed (cc->keepalive_period,
232 &send_keepalive,
233 cc);
234#endif
235 cc->state = CADET_CONNECTION_READY; 307 cc->state = CADET_CONNECTION_READY;
236 if (GNUNET_YES == cc->mqm_ready) 308 if (GNUNET_YES == cc->mqm_ready)
309 {
237 cc->ready_cb (cc->ready_cb_cls, 310 cc->ready_cb (cc->ready_cb_cls,
238 GNUNET_YES); 311 GNUNET_YES);
312 if ( (NULL == cc->keepalive_qe) &&
313 (GNUNET_YES == cc->mqm_ready) &&
314 (NULL == cc->task) )
315 cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
316 &send_keepalive,
317 cc);
318 }
239} 319}
240 320
241 321
@@ -288,7 +368,8 @@ GCC_handle_encrypted (struct CadetConnection *cc,
288 368
289 369
290/** 370/**
291 * Send a CREATE message to the first hop. 371 * Send a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE message to the
372 * first hop.
292 * 373 *
293 * @param cls the `struct CadetConnection` to initiate 374 * @param cls the `struct CadetConnection` to initiate
294 */ 375 */
@@ -459,6 +540,19 @@ manage_first_hop_mq (void *cls,
459 case CADET_CONNECTION_READY: 540 case CADET_CONNECTION_READY:
460 cc->ready_cb (cc->ready_cb_cls, 541 cc->ready_cb (cc->ready_cb_cls,
461 GNUNET_YES); 542 GNUNET_YES);
543 if ( (NULL == cc->keepalive_qe) &&
544 (GNUNET_YES == cc->mqm_ready) &&
545 (NULL == cc->task) )
546 {
547 LOG (GNUNET_ERROR_TYPE_DEBUG,
548 "Scheduling keepalive for %s in %s\n",
549 GCC_2s (cc),
550 GNUNET_STRINGS_relative_time_to_string (keepalive_period,
551 GNUNET_YES));
552 cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
553 &send_keepalive,
554 cc);
555 }
462 break; 556 break;
463 } 557 }
464} 558}
@@ -610,6 +704,11 @@ GCC_transmit (struct CadetConnection *cc,
610 GNUNET_assert (GNUNET_YES == cc->mqm_ready); 704 GNUNET_assert (GNUNET_YES == cc->mqm_ready);
611 GNUNET_assert (CADET_CONNECTION_READY == cc->state); 705 GNUNET_assert (CADET_CONNECTION_READY == cc->state);
612 cc->mqm_ready = GNUNET_NO; 706 cc->mqm_ready = GNUNET_NO;
707 if (NULL != cc->task)
708 {
709 GNUNET_SCHEDULER_cancel (cc->task);
710 cc->task = NULL;
711 }
613 GCP_send (cc->mq_man, 712 GCP_send (cc->mq_man,
614 env); 713 env);
615} 714}
diff --git a/src/cadet/gnunet-service-cadet-new_paths.c b/src/cadet/gnunet-service-cadet-new_paths.c
index 685656ec3..8a4d7bbf8 100644
--- a/src/cadet/gnunet-service-cadet-new_paths.c
+++ b/src/cadet/gnunet-service-cadet-new_paths.c
@@ -24,6 +24,11 @@
24 * @author Christian Grothoff 24 * @author Christian Grothoff
25 * 25 *
26 * TODO: 26 * TODO:
27 * - currently only allowing one unique connection per path,
28 * but need to allow 2 in case WE are establishing one from A to B
29 * while at the same time B establishes one to A.
30 * Also, must not ASSERT if B establishes a 2nd one to us.
31 * Need to have some reasonable tie-breaking to only keep ONE.
27 * - path desirability score calculations are not done 32 * - path desirability score calculations are not done
28 */ 33 */
29#include "platform.h" 34#include "platform.h"
diff --git a/src/cadet/gnunet-service-cadet-new_tunnels.c b/src/cadet/gnunet-service-cadet-new_tunnels.c
index fd8335486..03067a605 100644
--- a/src/cadet/gnunet-service-cadet-new_tunnels.c
+++ b/src/cadet/gnunet-service-cadet-new_tunnels.c
@@ -24,6 +24,8 @@
24 * @author Christian Grothoff 24 * @author Christian Grothoff
25 * 25 *
26 * FIXME: 26 * FIXME:
27 * - implement keepalive
28 * - implement rekeying
27 * - check KX estate machine -- make sure it is never stuck! 29 * - check KX estate machine -- make sure it is never stuck!
28 * - clean up KX logic, including adding sender authentication 30 * - clean up KX logic, including adding sender authentication
29 * - implement connection management (evaluate, kill old ones, 31 * - implement connection management (evaluate, kill old ones,
@@ -1961,7 +1963,7 @@ GCT_consider_path (struct CadetTunnel *t,
1961 1963
1962 1964
1963/** 1965/**
1964 * NOT IMPLEMENTED. 1966 * We got a keepalive. Track in statistics.
1965 * 1967 *
1966 * @param cls the `struct CadetTunnel` for which we decrypted the message 1968 * @param cls the `struct CadetTunnel` for which we decrypted the message
1967 * @param msg the message we received on the tunnel 1969 * @param msg the message we received on the tunnel
@@ -1972,7 +1974,13 @@ handle_plaintext_keepalive (void *cls,
1972{ 1974{
1973 struct CadetTunnel *t = cls; 1975 struct CadetTunnel *t = cls;
1974 1976
1975 GNUNET_break (0); // FIXME 1977 LOG (GNUNET_ERROR_TYPE_DEBUG,
1978 "Received KEEPALIVE on tunnel %s\n",
1979 GCT_2s (t));
1980 GNUNET_STATISTICS_update (stats,
1981 "# keepalives received",
1982 1,
1983 GNUNET_NO);
1976} 1984}
1977 1985
1978 1986
diff --git a/src/cadet/test_cadet.c b/src/cadet/test_cadet.c
index 3a1042eba..efc4f96b3 100644
--- a/src/cadet/test_cadet.c
+++ b/src/cadet/test_cadet.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2011 GNUnet e.V. 3 Copyright (C) 2011, 2017 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published 6 it under the terms of the GNU General Public License as published
@@ -64,7 +64,7 @@ static int test;
64/** 64/**
65 * String with test name 65 * String with test name
66 */ 66 */
67char *test_name; 67static char *test_name;
68 68
69/** 69/**
70 * Flag to send traffic leaf->root in speed tests to test BCK_ACK logic. 70 * Flag to send traffic leaf->root in speed tests to test BCK_ACK logic.
@@ -79,32 +79,32 @@ static int ok;
79/** 79/**
80 * Number of events expected to conclude the test successfully. 80 * Number of events expected to conclude the test successfully.
81 */ 81 */
82int ok_goal; 82static int ok_goal;
83 83
84/** 84/**
85 * Size of each test packet 85 * Size of each test packet
86 */ 86 */
87size_t size_payload = sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t); 87static size_t size_payload = sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t);
88 88
89/** 89/**
90 * Operation to get peer ids. 90 * Operation to get peer ids.
91 */ 91 */
92struct GNUNET_TESTBED_Operation *t_op[2]; 92static struct GNUNET_TESTBED_Operation *t_op[2];
93 93
94/** 94/**
95 * Peer ids. 95 * Peer ids.
96 */ 96 */
97struct GNUNET_PeerIdentity *p_id[2]; 97static struct GNUNET_PeerIdentity *p_id[2];
98 98
99/** 99/**
100 * Port ID 100 * Port ID
101 */ 101 */
102struct GNUNET_HashCode port; 102static struct GNUNET_HashCode port;
103 103
104/** 104/**
105 * Peer ids counter. 105 * Peer ids counter.
106 */ 106 */
107unsigned int p_ids; 107static unsigned int p_ids;
108 108
109/** 109/**
110 * Is the setup initialized? 110 * Is the setup initialized?
@@ -345,12 +345,21 @@ shutdown_task (void *cls)
345 * operation has executed successfully. 345 * operation has executed successfully.
346 */ 346 */
347static void 347static void
348stats_cont (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg) 348stats_cont (void *cls,
349 struct GNUNET_TESTBED_Operation *op,
350 const char *emsg)
349{ 351{
350 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " KA sent: %u, KA received: %u\n", 352 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
351 ka_sent, ka_received); 353 " KA sent: %u, KA received: %u\n",
352 if (KEEPALIVE == test && (ka_sent < 2 || ka_sent > ka_received + 1)) 354 ka_sent,
355 ka_received);
356 if ( (KEEPALIVE == test) &&
357 ( (ka_sent < 2) ||
358 (ka_sent > ka_received + 1)) )
359 {
360 GNUNET_break (0);
353 ok--; 361 ok--;
362 }
354 GNUNET_TESTBED_operation_done (stats_op); 363 GNUNET_TESTBED_operation_done (stats_op);
355 364
356 if (NULL != disconnect_task) 365 if (NULL != disconnect_task)
@@ -439,10 +448,11 @@ gather_stats_and_exit (void *cls)
439static void 448static void
440abort_test (long line) 449abort_test (long line)
441{ 450{
442 if (disconnect_task != NULL) 451 if (NULL != disconnect_task)
443 { 452 {
444 GNUNET_SCHEDULER_cancel (disconnect_task); 453 GNUNET_SCHEDULER_cancel (disconnect_task);
445 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Aborting test from %ld\n", line); 454 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
455 "Aborting test from %ld\n", line);
446 disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, 456 disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers,
447 (void *) line); 457 (void *) line);
448 } 458 }
diff --git a/src/core/core_api.c b/src/core/core_api.c
index 18b07068f..afae20850 100644
--- a/src/core/core_api.c
+++ b/src/core/core_api.c
@@ -336,7 +336,6 @@ core_mq_send_impl (struct GNUNET_MQ_Handle *mq,
336 env = GNUNET_MQ_msg (smr, 336 env = GNUNET_MQ_msg (smr,
337 GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST); 337 GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST);
338 smr->priority = htonl ((uint32_t) priority); 338 smr->priority = htonl ((uint32_t) priority);
339 // smr->deadline = GNUNET_TIME_absolute_hton (deadline);
340 smr->peer = pr->peer; 339 smr->peer = pr->peer;
341 smr->reserved = htonl (0); 340 smr->reserved = htonl (0);
342 smr->size = htons (msize); 341 smr->size = htons (msize);
@@ -349,7 +348,6 @@ core_mq_send_impl (struct GNUNET_MQ_Handle *mq,
349 GNUNET_MESSAGE_TYPE_CORE_SEND, 348 GNUNET_MESSAGE_TYPE_CORE_SEND,
350 msg); 349 msg);
351 sm->priority = htonl ((uint32_t) priority); 350 sm->priority = htonl ((uint32_t) priority);
352 // sm->deadline = GNUNET_TIME_absolute_hton (deadline);
353 sm->peer = pr->peer; 351 sm->peer = pr->peer;
354 sm->cork = htonl ((uint32_t) cork); 352 sm->cork = htonl ((uint32_t) cork);
355 sm->reserved = htonl (0); 353 sm->reserved = htonl (0);
diff --git a/src/include/gnunet_container_lib.h b/src/include/gnunet_container_lib.h
index d2f8c5d9c..c77d82fd3 100644
--- a/src/include/gnunet_container_lib.h
+++ b/src/include/gnunet_container_lib.h
@@ -2092,8 +2092,8 @@ GNUNET_CONTAINER_multihashmap32_iterator_destroy (struct GNUNET_CONTAINER_MultiH
2092 element, \ 2092 element, \
2093 head)) ) \ 2093 head)) ) \
2094 { \ 2094 { \
2095 /* insert at head, e;e,emt < head */ \ 2095 /* insert at head, element < head */ \
2096 GNUNET_CONTAINER_DLL_insert (head, \ 2096 GNUNET_CONTAINER_DLL_insert (head, \
2097 tail, \ 2097 tail, \
2098 element); \ 2098 element); \
2099 } \ 2099 } \
@@ -2109,17 +2109,21 @@ GNUNET_CONTAINER_multihashmap32_iterator_destroy (struct GNUNET_CONTAINER_MultiH
2109 element, \ 2109 element, \
2110 pos)) \ 2110 pos)) \
2111 break; /* element < pos */ \ 2111 break; /* element < pos */ \
2112 if (NULL == pos) /* => element > tail */ \ 2112 if (NULL == pos) /* => element > tail */ \
2113 GNUNET_CONTAINER_DLL_insert_tail (head, \ 2113 { \
2114 tail, \ 2114 GNUNET_CONTAINER_DLL_insert_tail (head, \
2115 element); \ 2115 tail, \
2116 else /* prev < element < pos */ \ 2116 element); \
2117 GNUNET_CONTAINER_DLL_insert_after (head, \ 2117 } \
2118 tail, \ 2118 else /* prev < element < pos */ \
2119 element, \ 2119 { \
2120 pos->prev); \ 2120 GNUNET_CONTAINER_DLL_insert_after (head, \
2121 tail, \
2122 pos->prev, \
2123 element); \
2121 } \ 2124 } \
2122 } while (0) 2125 } \
2126} while (0)
2123 2127
2124 2128
2125/* ******************** Heap *************** */ 2129/* ******************** Heap *************** */
diff --git a/src/util/.gitignore b/src/util/.gitignore
index f207e07bf..a0cb43874 100644
--- a/src/util/.gitignore
+++ b/src/util/.gitignore
@@ -22,6 +22,7 @@ test_connection_timeout.nc
22test_connection_timeout_no_connect.nc 22test_connection_timeout_no_connect.nc
23test_connection_transmit_cancel.nc 23test_connection_transmit_cancel.nc
24test_container_bloomfilter 24test_container_bloomfilter
25test_container_dll
25test_container_heap 26test_container_heap
26test_container_meta_data 27test_container_meta_data
27test_container_multihashmap 28test_container_multihashmap
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index f49aee17f..c666b017d 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -273,6 +273,7 @@ check_PROGRAMS = \
273 test_common_logging \ 273 test_common_logging \
274 test_configuration \ 274 test_configuration \
275 test_container_bloomfilter \ 275 test_container_bloomfilter \
276 test_container_dll \
276 test_container_meta_data \ 277 test_container_meta_data \
277 test_container_multihashmap \ 278 test_container_multihashmap \
278 test_container_multihashmap32 \ 279 test_container_multihashmap32 \
@@ -398,6 +399,11 @@ test_container_bloomfilter_SOURCES = \
398test_container_bloomfilter_LDADD = \ 399test_container_bloomfilter_LDADD = \
399 libgnunetutil.la 400 libgnunetutil.la
400 401
402test_container_dll_SOURCES = \
403 test_container_dll.c
404test_container_dll_LDADD = \
405 libgnunetutil.la
406
401test_container_meta_data_SOURCES = \ 407test_container_meta_data_SOURCES = \
402 test_container_meta_data.c 408 test_container_meta_data.c
403test_container_meta_data_LDADD = \ 409test_container_meta_data_LDADD = \
diff --git a/src/util/test_container_dll.c b/src/util/test_container_dll.c
new file mode 100644
index 000000000..8ad08423a
--- /dev/null
+++ b/src/util/test_container_dll.c
@@ -0,0 +1,115 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2017 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19 */
20
21/**
22 * @author Christian Grothoff
23 * @file util/test_container_dll.c
24 * @brief Test of DLL operations
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29
30/**
31 * Element in the DLL.
32 */
33struct Element
34{
35 /**
36 * Required pointer to previous element.
37 */
38 struct Element *prev;
39
40 /**
41 * Required pointer to next element.
42 */
43 struct Element *next;
44
45 /**
46 * Used to sort.
47 */
48 unsigned int value;
49};
50
51
52/**
53 * Compare two elements.
54 *
55 * @param cls closure, NULL
56 * @param e1 an element of to sort
57 * @param e2 another element to sort
58 * @return #GNUNET_YES if @e1 < @e2, otherwise #GNUNET_NO
59 */
60static int
61cmp_elem (void *cls,
62 struct Element *e1,
63 struct Element *e2)
64{
65 if (e1->value == e2->value)
66 return 0;
67 return (e1->value < e2->value) ? 1 : -1;
68}
69
70
71int
72main (int argc, char **argv)
73{
74 unsigned int values2[] = {
75 4, 5, 8, 6, 9, 3, 7, 2, 6, 1, 0
76 };
77 unsigned int values[] = {
78 1, 3, 2, 0
79 };
80 struct Element *head = NULL;
81 struct Element *tail = NULL;
82 struct Element *e;
83 unsigned int want;
84
85 GNUNET_log_setup ("test-container-dll",
86 "WARNING",
87 NULL);
88 for (unsigned int off=0;
89 0 != values[off];
90 off++)
91 {
92 e = GNUNET_new (struct Element);
93 e->value = values[off];
94 GNUNET_CONTAINER_DLL_insert_sorted (struct Element,
95 cmp_elem,
96 NULL,
97 head,
98 tail,
99 e);
100 }
101
102 want = 1;
103 while (NULL != (e = head))
104 {
105 GNUNET_assert (e->value == want);
106 GNUNET_CONTAINER_DLL_remove (head,
107 tail,
108 e);
109 GNUNET_free (e);
110 want++;
111 }
112 return 0;
113}
114
115/* end of test_container_heap.c */