diff options
author | xrs <xrs@mail36.net> | 2017-01-25 21:17:13 +0100 |
---|---|---|
committer | xrs <xrs@mail36.net> | 2017-01-25 21:17:44 +0100 |
commit | f477898f001e61471582b24296f6cc22cf3444ea (patch) | |
tree | 6cd0e62ada4cf89004382d3d02ce319f5bd1cbc1 | |
parent | e76078deb931e473565a0d718f837d60e1b9caf8 (diff) | |
parent | a3e5e258714ea71f204be398d1384a3cdfd11e56 (diff) | |
download | gnunet-f477898f001e61471582b24296f6cc22cf3444ea.tar.gz gnunet-f477898f001e61471582b24296f6cc22cf3444ea.zip |
Merge branch 'master' of ssh://gnunet.org/gnunet
-rw-r--r-- | src/cadet/.gitignore | 1 | ||||
-rw-r--r-- | src/cadet/cadet.conf.in | 2 | ||||
-rw-r--r-- | src/cadet/gnunet-service-cadet-new.c | 17 | ||||
-rw-r--r-- | src/cadet/gnunet-service-cadet-new.h | 5 | ||||
-rw-r--r-- | src/cadet/gnunet-service-cadet-new_channel.c | 478 | ||||
-rw-r--r-- | src/cadet/gnunet-service-cadet-new_connection.c | 115 | ||||
-rw-r--r-- | src/cadet/gnunet-service-cadet-new_paths.c | 5 | ||||
-rw-r--r-- | src/cadet/gnunet-service-cadet-new_tunnels.c | 12 | ||||
-rw-r--r-- | src/cadet/test_cadet.c | 38 | ||||
-rw-r--r-- | src/core/core_api.c | 2 | ||||
-rw-r--r-- | src/include/gnunet_container_lib.h | 28 | ||||
-rw-r--r-- | src/util/.gitignore | 1 | ||||
-rw-r--r-- | src/util/Makefile.am | 6 | ||||
-rw-r--r-- | src/util/test_container_dll.c | 115 |
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 | |||
19 | test_cadet_5_speed_reliable_backwards | 19 | test_cadet_5_speed_reliable_backwards |
20 | test_cadet_local | 20 | test_cadet_local |
21 | test_cadet_single | 21 | test_cadet_single |
22 | gnunet-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 | |||
3 | AUTOSTART = @AUTOSTART@ | 3 | AUTOSTART = @AUTOSTART@ |
4 | @JAVAPORT@PORT = 2096 | 4 | @JAVAPORT@PORT = 2096 |
5 | HOSTNAME = localhost | 5 | HOSTNAME = localhost |
6 | BINARY = gnunet-service-cadet | 6 | BINARY = gnunet-service-cadet-new |
7 | # PREFIX = valgrind --leak-check=yes | 7 | # PREFIX = valgrind --leak-check=yes |
8 | ACCEPT_FROM = 127.0.0.1; | 8 | ACCEPT_FROM = 127.0.0.1; |
9 | ACCEPT_FROM6 = ::1; | 9 | ACCEPT_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 | */ |
184 | struct GNUNET_TIME_Relative ratchet_time; | 184 | struct GNUNET_TIME_Relative ratchet_time; |
185 | 185 | ||
186 | /** | ||
187 | * How frequently do we send KEEPALIVE messages on idle connections? | ||
188 | */ | ||
189 | struct 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; | |||
226 | extern struct GNUNET_TIME_Relative ratchet_time; | 226 | extern struct GNUNET_TIME_Relative ratchet_time; |
227 | 227 | ||
228 | /** | 228 | /** |
229 | * How frequently do we send KEEPALIVE messages on idle connections? | ||
230 | */ | ||
231 | extern 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 | */ |
231 | extern int shutting_down; | 236 | extern 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 | */ | ||
1251 | static void | ||
1252 | data_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 | */ | ||
1261 | static void | ||
1262 | retry_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 | */ | ||
1288 | static void | ||
1289 | handle_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 | */ | ||
1295 | static void | ||
1296 | data_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 | */ |
1305 | static void | 1438 | static int |
1306 | retry_transmission (void *cls) | 1439 | cmp_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 | */ | ||
229 | static void | ||
230 | send_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 | */ | ||
239 | static void | ||
240 | keepalive_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 | */ | ||
259 | static void | ||
260 | send_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 | */ |
67 | char *test_name; | 67 | static 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 | */ |
82 | int ok_goal; | 82 | static int ok_goal; |
83 | 83 | ||
84 | /** | 84 | /** |
85 | * Size of each test packet | 85 | * Size of each test packet |
86 | */ | 86 | */ |
87 | size_t size_payload = sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t); | 87 | static 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 | */ |
92 | struct GNUNET_TESTBED_Operation *t_op[2]; | 92 | static struct GNUNET_TESTBED_Operation *t_op[2]; |
93 | 93 | ||
94 | /** | 94 | /** |
95 | * Peer ids. | 95 | * Peer ids. |
96 | */ | 96 | */ |
97 | struct GNUNET_PeerIdentity *p_id[2]; | 97 | static struct GNUNET_PeerIdentity *p_id[2]; |
98 | 98 | ||
99 | /** | 99 | /** |
100 | * Port ID | 100 | * Port ID |
101 | */ | 101 | */ |
102 | struct GNUNET_HashCode port; | 102 | static struct GNUNET_HashCode port; |
103 | 103 | ||
104 | /** | 104 | /** |
105 | * Peer ids counter. | 105 | * Peer ids counter. |
106 | */ | 106 | */ |
107 | unsigned int p_ids; | 107 | static 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 | */ |
347 | static void | 347 | static void |
348 | stats_cont (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg) | 348 | stats_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) | |||
439 | static void | 448 | static void |
440 | abort_test (long line) | 449 | abort_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 | |||
22 | test_connection_timeout_no_connect.nc | 22 | test_connection_timeout_no_connect.nc |
23 | test_connection_transmit_cancel.nc | 23 | test_connection_transmit_cancel.nc |
24 | test_container_bloomfilter | 24 | test_container_bloomfilter |
25 | test_container_dll | ||
25 | test_container_heap | 26 | test_container_heap |
26 | test_container_meta_data | 27 | test_container_meta_data |
27 | test_container_multihashmap | 28 | test_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 = \ | |||
398 | test_container_bloomfilter_LDADD = \ | 399 | test_container_bloomfilter_LDADD = \ |
399 | libgnunetutil.la | 400 | libgnunetutil.la |
400 | 401 | ||
402 | test_container_dll_SOURCES = \ | ||
403 | test_container_dll.c | ||
404 | test_container_dll_LDADD = \ | ||
405 | libgnunetutil.la | ||
406 | |||
401 | test_container_meta_data_SOURCES = \ | 407 | test_container_meta_data_SOURCES = \ |
402 | test_container_meta_data.c | 408 | test_container_meta_data.c |
403 | test_container_meta_data_LDADD = \ | 409 | test_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 | */ | ||
33 | struct 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 | */ | ||
60 | static int | ||
61 | cmp_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 | |||
71 | int | ||
72 | main (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 */ | ||