aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2010-03-10 10:55:01 +0000
committerChristian Grothoff <christian@grothoff.org>2010-03-10 10:55:01 +0000
commitf6c1d5c870dadddc88c8f501448e2951b1c900b7 (patch)
treebf40faddf1ca8d96ab8fc2840507ef025a87c4f5
parent02e738b91dff93aa75bfe38d5d58fdbd353f50be (diff)
downloadgnunet-f6c1d5c870dadddc88c8f501448e2951b1c900b7.tar.gz
gnunet-f6c1d5c870dadddc88c8f501448e2951b1c900b7.zip
keepalive PINGs
-rw-r--r--TODO1
-rw-r--r--src/core/gnunet-service-core.c201
-rw-r--r--src/include/gnunet_time_lib.h27
-rw-r--r--src/util/time.c36
4 files changed, 212 insertions, 53 deletions
diff --git a/TODO b/TODO
index b2f6166b5..bd58eaeec 100644
--- a/TODO
+++ b/TODO
@@ -13,7 +13,6 @@ away), in order in which they will likely be done:
13* ARM [Safey] 13* ARM [Safey]
14 14
15Urgent items (before announcing ng.gnunet.org): 15Urgent items (before announcing ng.gnunet.org):
16* core fails to do keepalive on idle connections => disconnect!
17* new webpage 16* new webpage
18 - run peer => have a 0.9.x hostlist 17 - run peer => have a 0.9.x hostlist
19=> Deploy(able) development network 18=> Deploy(able) development network
diff --git a/src/core/gnunet-service-core.c b/src/core/gnunet-service-core.c
index f63ccec88..b13ea023b 100644
--- a/src/core/gnunet-service-core.c
+++ b/src/core/gnunet-service-core.c
@@ -101,6 +101,11 @@
101#define MAX_PONG_DELAY GNUNET_TIME_relative_multiply (MAX_PING_DELAY, 2) 101#define MAX_PONG_DELAY GNUNET_TIME_relative_multiply (MAX_PING_DELAY, 2)
102 102
103/** 103/**
104 * What is the minimum frequency for a PING message?
105 */
106#define MIN_PING_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
107
108/**
104 * How often do we recalculate bandwidth quotas? 109 * How often do we recalculate bandwidth quotas?
105 */ 110 */
106#define QUOTA_UPDATE_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) 111#define QUOTA_UPDATE_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
@@ -477,6 +482,11 @@ struct Neighbour
477 GNUNET_SCHEDULER_TaskIdentifier quota_update_task; 482 GNUNET_SCHEDULER_TaskIdentifier quota_update_task;
478 483
479 /** 484 /**
485 * ID of task used for sending keep-alive pings.
486 */
487 GNUNET_SCHEDULER_TaskIdentifier keep_alive_task;
488
489 /**
480 * ID of task used for cleaning up dead neighbour entries. 490 * ID of task used for cleaning up dead neighbour entries.
481 */ 491 */
482 GNUNET_SCHEDULER_TaskIdentifier dead_clean_task; 492 GNUNET_SCHEDULER_TaskIdentifier dead_clean_task;
@@ -1074,6 +1084,8 @@ free_neighbour (struct Neighbour *n)
1074 GNUNET_SCHEDULER_cancel (sched, n->quota_update_task); 1084 GNUNET_SCHEDULER_cancel (sched, n->quota_update_task);
1075 if (n->dead_clean_task != GNUNET_SCHEDULER_NO_TASK) 1085 if (n->dead_clean_task != GNUNET_SCHEDULER_NO_TASK)
1076 GNUNET_SCHEDULER_cancel (sched, n->dead_clean_task); 1086 GNUNET_SCHEDULER_cancel (sched, n->dead_clean_task);
1087 if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK)
1088 GNUNET_SCHEDULER_cancel (sched, n->keep_alive_task);
1077 GNUNET_free_non_null (n->public_key); 1089 GNUNET_free_non_null (n->public_key);
1078 GNUNET_free_non_null (n->pending_ping); 1090 GNUNET_free_non_null (n->pending_ping);
1079 GNUNET_free_non_null (n->pending_pong); 1091 GNUNET_free_non_null (n->pending_pong);
@@ -1082,6 +1094,53 @@ free_neighbour (struct Neighbour *n)
1082 1094
1083 1095
1084/** 1096/**
1097 * Check if we have encrypted messages for the specified neighbour
1098 * pending, and if so, check with the transport about sending them
1099 * out.
1100 *
1101 * @param n neighbour to check.
1102 */
1103static void process_encrypted_neighbour_queue (struct Neighbour *n);
1104
1105
1106/**
1107 * Encrypt size bytes from in and write the result to out. Use the
1108 * key for outbound traffic of the given neighbour.
1109 *
1110 * @param n neighbour we are sending to
1111 * @param iv initialization vector to use
1112 * @param in ciphertext
1113 * @param out plaintext
1114 * @param size size of in/out
1115 * @return GNUNET_OK on success
1116 */
1117static int
1118do_encrypt (struct Neighbour *n,
1119 const GNUNET_HashCode * iv,
1120 const void *in, void *out, size_t size)
1121{
1122 if (size != (uint16_t) size)
1123 {
1124 GNUNET_break (0);
1125 return GNUNET_NO;
1126 }
1127 GNUNET_assert (size ==
1128 GNUNET_CRYPTO_aes_encrypt (in,
1129 (uint16_t) size,
1130 &n->encrypt_key,
1131 (const struct
1132 GNUNET_CRYPTO_AesInitializationVector
1133 *) iv, out));
1134#if DEBUG_CORE
1135 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1136 "Encrypted %u bytes for `%4s' using key %u\n", size,
1137 GNUNET_i2s (&n->peer), n->encrypt_key.crc32);
1138#endif
1139 return GNUNET_OK;
1140}
1141
1142
1143/**
1085 * Consider freeing the given neighbour since we may not need 1144 * Consider freeing the given neighbour since we may not need
1086 * to keep it around anymore. 1145 * to keep it around anymore.
1087 * 1146 *
@@ -1092,6 +1151,68 @@ consider_free_neighbour (struct Neighbour *n);
1092 1151
1093 1152
1094/** 1153/**
1154 * Task triggered when a neighbour entry is about to time out
1155 * (and we should prevent this by sending a PING).
1156 *
1157 * @param cls the 'struct Neighbour'
1158 * @param tc scheduler context (not used)
1159 */
1160static void
1161send_keep_alive (void *cls,
1162 const struct GNUNET_SCHEDULER_TaskContext *tc)
1163{
1164 struct Neighbour *n = cls;
1165 struct GNUNET_TIME_Relative retry;
1166 struct GNUNET_TIME_Relative left;
1167 struct MessageEntry *me;
1168 struct PingMessage pp;
1169 struct PingMessage *pm;
1170
1171 n->keep_alive_task = GNUNET_SCHEDULER_NO_TASK;
1172 /* send PING */
1173 me = GNUNET_malloc (sizeof (struct MessageEntry) +
1174 sizeof (struct PingMessage));
1175 me->deadline = GNUNET_TIME_relative_to_absolute (MAX_PING_DELAY);
1176 me->priority = PING_PRIORITY;
1177 me->size = sizeof (struct PingMessage);
1178 n->encrypted_tail->next = me;
1179 n->encrypted_tail = me;
1180 pm = (struct PingMessage *) &me[1];
1181 pm->header.size = htons (sizeof (struct PingMessage));
1182 pm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PING);
1183 pp.challenge = htonl (n->ping_challenge);
1184 pp.target = n->peer;
1185#if DEBUG_CORE
1186 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1187 "Encrypting `%s' and `%s' messages for `%4s'.\n",
1188 "SET_KEY", "PING", GNUNET_i2s (&n->peer));
1189 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1190 "Sending `%s' to `%4s' with challenge %u encrypted using key %u\n",
1191 "PING",
1192 GNUNET_i2s (&n->peer), n->ping_challenge, n->encrypt_key.crc32);
1193#endif
1194 do_encrypt (n,
1195 &n->peer.hashPubKey,
1196 &pp.challenge,
1197 &pm->challenge,
1198 sizeof (struct PingMessage) -
1199 sizeof (struct GNUNET_MessageHeader));
1200 process_encrypted_neighbour_queue (n);
1201 /* reschedule PING job */
1202 left = GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_add (n->last_activity,
1203 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT));
1204 retry = GNUNET_TIME_relative_max (GNUNET_TIME_relative_divide (left, 2),
1205 MIN_PING_FREQUENCY);
1206 n->keep_alive_task
1207 = GNUNET_SCHEDULER_add_delayed (sched,
1208 GNUNET_TIME_relative_divide (left, 2),
1209 &send_keep_alive,
1210 n);
1211
1212}
1213
1214
1215/**
1095 * Task triggered when a neighbour entry might have gotten stale. 1216 * Task triggered when a neighbour entry might have gotten stale.
1096 * 1217 *
1097 * @param cls the 'struct Neighbour' 1218 * @param cls the 'struct Neighbour'
@@ -1102,6 +1223,7 @@ consider_free_task (void *cls,
1102 const struct GNUNET_SCHEDULER_TaskContext *tc) 1223 const struct GNUNET_SCHEDULER_TaskContext *tc)
1103{ 1224{
1104 struct Neighbour *n = cls; 1225 struct Neighbour *n = cls;
1226
1105 n->dead_clean_task = GNUNET_SCHEDULER_NO_TASK; 1227 n->dead_clean_task = GNUNET_SCHEDULER_NO_TASK;
1106 consider_free_neighbour (n); 1228 consider_free_neighbour (n);
1107} 1229}
@@ -1127,7 +1249,7 @@ consider_free_neighbour (struct Neighbour *n)
1127 return; /* no chance */ 1249 return; /* no chance */
1128 1250
1129 left = GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_add (n->last_activity, 1251 left = GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_add (n->last_activity,
1130 MAX_PONG_DELAY)); 1252 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT));
1131 if (left.value > 0) 1253 if (left.value > 0)
1132 { 1254 {
1133 if (n->dead_clean_task != GNUNET_SCHEDULER_NO_TASK) 1255 if (n->dead_clean_task != GNUNET_SCHEDULER_NO_TASK)
@@ -1157,16 +1279,6 @@ consider_free_neighbour (struct Neighbour *n)
1157 1279
1158 1280
1159/** 1281/**
1160 * Check if we have encrypted messages for the specified neighbour
1161 * pending, and if so, check with the transport about sending them
1162 * out.
1163 *
1164 * @param n neighbour to check.
1165 */
1166static void process_encrypted_neighbour_queue (struct Neighbour *n);
1167
1168
1169/**
1170 * Function called when the transport service is ready to 1282 * Function called when the transport service is ready to
1171 * receive an encrypted message for the respective peer 1283 * receive an encrypted message for the respective peer
1172 * 1284 *
@@ -1330,43 +1442,6 @@ do_decrypt (struct Neighbour *n,
1330 1442
1331 1443
1332/** 1444/**
1333 * Encrypt size bytes from in and write the result to out. Use the
1334 * key for outbound traffic of the given neighbour.
1335 *
1336 * @param n neighbour we are sending to
1337 * @param iv initialization vector to use
1338 * @param in ciphertext
1339 * @param out plaintext
1340 * @param size size of in/out
1341 * @return GNUNET_OK on success
1342 */
1343static int
1344do_encrypt (struct Neighbour *n,
1345 const GNUNET_HashCode * iv,
1346 const void *in, void *out, size_t size)
1347{
1348 if (size != (uint16_t) size)
1349 {
1350 GNUNET_break (0);
1351 return GNUNET_NO;
1352 }
1353 GNUNET_assert (size ==
1354 GNUNET_CRYPTO_aes_encrypt (in,
1355 (uint16_t) size,
1356 &n->encrypt_key,
1357 (const struct
1358 GNUNET_CRYPTO_AesInitializationVector
1359 *) iv, out));
1360#if DEBUG_CORE
1361 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1362 "Encrypted %u bytes for `%4s' using key %u\n", size,
1363 GNUNET_i2s (&n->peer), n->encrypt_key.crc32);
1364#endif
1365 return GNUNET_OK;
1366}
1367
1368
1369/**
1370 * Select messages for transmission. This heuristic uses a combination 1445 * Select messages for transmission. This heuristic uses a combination
1371 * of earliest deadline first (EDF) scheduling (with bounded horizon) 1446 * of earliest deadline first (EDF) scheduling (with bounded horizon)
1372 * and priority-based discard (in case no feasible schedule exist) and 1447 * and priority-based discard (in case no feasible schedule exist) and
@@ -2645,9 +2720,16 @@ handle_pong (struct Neighbour *n,
2645 cnm.peer = n->peer; 2720 cnm.peer = n->peer;
2646 send_to_all_clients (&cnm.header, GNUNET_YES, GNUNET_CORE_OPTION_SEND_CONNECT); 2721 send_to_all_clients (&cnm.header, GNUNET_YES, GNUNET_CORE_OPTION_SEND_CONNECT);
2647 process_encrypted_neighbour_queue (n); 2722 process_encrypted_neighbour_queue (n);
2648 break; 2723 /* fall-through! */
2649 case PEER_STATE_KEY_CONFIRMED: 2724 case PEER_STATE_KEY_CONFIRMED:
2650 /* duplicate PONG? */ 2725 n->last_activity = GNUNET_TIME_absolute_get ();
2726 if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK)
2727 GNUNET_SCHEDULER_cancel (sched, n->keep_alive_task);
2728 n->keep_alive_task
2729 = GNUNET_SCHEDULER_add_delayed (sched,
2730 GNUNET_TIME_relative_divide (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, 2),
2731 &send_keep_alive,
2732 n);
2651 break; 2733 break;
2652 default: 2734 default:
2653 GNUNET_break (0); 2735 GNUNET_break (0);
@@ -2711,8 +2793,9 @@ handle_set_key (struct Neighbour *n, const struct SetKeyMessage *m)
2711 sizeof (struct GNUNET_PeerIdentity))) 2793 sizeof (struct GNUNET_PeerIdentity)))
2712 { 2794 {
2713 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 2795 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2714 _("Received `%s' message that was not for me. Ignoring.\n"), 2796 _("Received `%s' message that was for `%s', not for me. Ignoring.\n"),
2715 "SET_KEY"); 2797 "SET_KEY",
2798 GNUNET_i2s (&m->target));
2716 return; 2799 return;
2717 } 2800 }
2718 if ((ntohl (m->purpose.size) != 2801 if ((ntohl (m->purpose.size) !=
@@ -3106,6 +3189,13 @@ handle_encrypted_message (struct Neighbour *n,
3106 NULL, NULL); 3189 NULL, NULL);
3107 } 3190 }
3108 n->last_activity = GNUNET_TIME_absolute_get (); 3191 n->last_activity = GNUNET_TIME_absolute_get ();
3192 if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK)
3193 GNUNET_SCHEDULER_cancel (sched, n->keep_alive_task);
3194 n->keep_alive_task
3195 = GNUNET_SCHEDULER_add_delayed (sched,
3196 GNUNET_TIME_relative_divide (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, 2),
3197 &send_keep_alive,
3198 n);
3109 off = sizeof (struct EncryptedMessage); 3199 off = sizeof (struct EncryptedMessage);
3110 deliver_messages (n, buf, size, off); 3200 deliver_messages (n, buf, size, off);
3111} 3201}
@@ -3233,6 +3323,13 @@ handle_transport_receive (void *cls,
3233 n->last_activity = now; 3323 n->last_activity = now;
3234 if (!up) 3324 if (!up)
3235 n->time_established = now; 3325 n->time_established = now;
3326 if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK)
3327 GNUNET_SCHEDULER_cancel (sched, n->keep_alive_task);
3328 n->keep_alive_task
3329 = GNUNET_SCHEDULER_add_delayed (sched,
3330 GNUNET_TIME_relative_divide (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, 2),
3331 &send_keep_alive,
3332 n);
3236 } 3333 }
3237} 3334}
3238 3335
diff --git a/src/include/gnunet_time_lib.h b/src/include/gnunet_time_lib.h
index 8336a04fd..fa443a463 100644
--- a/src/include/gnunet_time_lib.h
+++ b/src/include/gnunet_time_lib.h
@@ -204,6 +204,20 @@ struct GNUNET_TIME_Relative GNUNET_TIME_relative_min (struct
204 struct 204 struct
205 GNUNET_TIME_Relative t2); 205 GNUNET_TIME_Relative t2);
206 206
207
208/**
209 * Return the maximum of two relative time values.
210 *
211 * @param t1 first timestamp
212 * @param t2 other timestamp
213 * @return timestamp that is larger
214 */
215struct GNUNET_TIME_Relative GNUNET_TIME_relative_max (struct
216 GNUNET_TIME_Relative
217 t1,
218 struct
219 GNUNET_TIME_Relative t2);
220
207/** 221/**
208 * Return the minimum of two absolute time values. 222 * Return the minimum of two absolute time values.
209 * 223 *
@@ -314,6 +328,19 @@ struct GNUNET_TIME_Relative GNUNET_TIME_relative_multiply (struct
314 factor); 328 factor);
315 329
316/** 330/**
331 * Divide relative time by a given factor.
332 *
333 * @param rel some duration
334 * @param factor integer to divide by
335 * @return FOREVER if rel=FOREVER or factor==0; otherwise rel/factor
336 */
337struct GNUNET_TIME_Relative GNUNET_TIME_relative_divide (struct
338 GNUNET_TIME_Relative
339 rel,
340 unsigned int
341 factor);
342
343/**
317 * Add relative times together. 344 * Add relative times together.
318 * 345 *
319 * @param a1 some relative time 346 * @param a1 some relative time
diff --git a/src/util/time.c b/src/util/time.c
index 36a3c8631..ce2f9517f 100644
--- a/src/util/time.c
+++ b/src/util/time.c
@@ -137,6 +137,22 @@ GNUNET_TIME_relative_min (struct
137} 137}
138 138
139 139
140/**
141 * Return the maximum of two relative time values.
142 *
143 * @param t1 first timestamp
144 * @param t2 other timestamp
145 * @return timestamp that is larger
146 */
147struct GNUNET_TIME_Relative
148GNUNET_TIME_relative_max (struct
149 GNUNET_TIME_Relative
150 t1, struct GNUNET_TIME_Relative t2)
151{
152 return (t1.value > t2.value) ? t1 : t2;
153}
154
155
140 156
141/** 157/**
142 * Return the minimum of two relative time values. 158 * Return the minimum of two relative time values.
@@ -277,6 +293,26 @@ GNUNET_TIME_relative_multiply (struct GNUNET_TIME_Relative rel,
277 293
278 294
279/** 295/**
296 * Divide relative time by a given factor.
297 *
298 * @param rel some duration
299 * @param factor integer to divide by
300 * @return FOREVER if rel=FOREVER or factor==0; otherwise rel/factor
301 */
302struct GNUNET_TIME_Relative
303GNUNET_TIME_relative_divide (struct GNUNET_TIME_Relative rel,
304 unsigned int factor)
305{
306 struct GNUNET_TIME_Relative ret;
307 if ( (factor == 0) ||
308 (rel.value == GNUNET_TIME_UNIT_FOREVER_REL.value) )
309 return GNUNET_TIME_UNIT_FOREVER_REL;
310 ret.value = rel.value / (unsigned long long) factor;
311 return ret;
312}
313
314
315/**
280 * Calculate the estimate time of arrival/completion 316 * Calculate the estimate time of arrival/completion
281 * for an operation. 317 * for an operation.
282 * 318 *