diff options
author | Christian Grothoff <christian@grothoff.org> | 2014-04-23 11:04:53 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2014-04-23 11:04:53 +0000 |
commit | a19683a4b76e10843c4e75db928bac5750c6430a (patch) | |
tree | 7aeff0c4d49b5f3750c569216e77912016fd5a81 /src/core/gnunet-service-core_sessions.c | |
parent | 21bac846638fbbbe2b03672295d4f14fc3ceb839 (diff) | |
download | gnunet-a19683a4b76e10843c4e75db928bac5750c6430a.tar.gz gnunet-a19683a4b76e10843c4e75db928bac5750c6430a.zip |
fix #3348: send typemap confirmation messages, perform faster typemap retransmissions for unconfirmed typemaps, restart retransmissions on reconnect
Diffstat (limited to 'src/core/gnunet-service-core_sessions.c')
-rw-r--r-- | src/core/gnunet-service-core_sessions.c | 232 |
1 files changed, 194 insertions, 38 deletions
diff --git a/src/core/gnunet-service-core_sessions.c b/src/core/gnunet-service-core_sessions.c index eb0013790..09bb3d6c4 100644 --- a/src/core/gnunet-service-core_sessions.c +++ b/src/core/gnunet-service-core_sessions.c | |||
@@ -137,6 +137,12 @@ struct Session | |||
137 | GNUNET_SCHEDULER_TaskIdentifier typemap_task; | 137 | GNUNET_SCHEDULER_TaskIdentifier typemap_task; |
138 | 138 | ||
139 | /** | 139 | /** |
140 | * Retransmission delay we currently use for the typemap | ||
141 | * transmissions (if not confirmed). | ||
142 | */ | ||
143 | struct GNUNET_TIME_Relative typemap_delay; | ||
144 | |||
145 | /** | ||
140 | * Is the neighbour queue empty and thus ready for us | 146 | * Is the neighbour queue empty and thus ready for us |
141 | * to transmit an encrypted message? | 147 | * to transmit an encrypted message? |
142 | */ | 148 | */ |
@@ -151,6 +157,34 @@ struct Session | |||
151 | }; | 157 | }; |
152 | 158 | ||
153 | 159 | ||
160 | GNUNET_NETWORK_STRUCT_BEGIN | ||
161 | |||
162 | /** | ||
163 | * Message sent to confirm that a typemap was received. | ||
164 | */ | ||
165 | struct TypeMapConfirmationMessage | ||
166 | { | ||
167 | |||
168 | /** | ||
169 | * Header with type #GNUNET_MESSAGE_TYPE_CORE_CONFIRM_TYPE_MAP. | ||
170 | */ | ||
171 | struct GNUNET_MessageHeader header; | ||
172 | |||
173 | /** | ||
174 | * Reserved, always zero. | ||
175 | */ | ||
176 | uint32_t reserved GNUNET_PACKED; | ||
177 | |||
178 | /** | ||
179 | * Hash of the (decompressed) type map that was received. | ||
180 | */ | ||
181 | struct GNUNET_HashCode tm_hash; | ||
182 | |||
183 | }; | ||
184 | |||
185 | GNUNET_NETWORK_STRUCT_END | ||
186 | |||
187 | |||
154 | /** | 188 | /** |
155 | * Map of peer identities to `struct Session`. | 189 | * Map of peer identities to `struct Session`. |
156 | */ | 190 | */ |
@@ -203,10 +237,16 @@ GSC_SESSIONS_end (const struct GNUNET_PeerIdentity *pid) | |||
203 | } | 237 | } |
204 | while (NULL != (sme = session->sme_head)) | 238 | while (NULL != (sme = session->sme_head)) |
205 | { | 239 | { |
206 | GNUNET_CONTAINER_DLL_remove (session->sme_head, session->sme_tail, sme); | 240 | GNUNET_CONTAINER_DLL_remove (session->sme_head, |
241 | session->sme_tail, | ||
242 | sme); | ||
207 | GNUNET_free (sme); | 243 | GNUNET_free (sme); |
208 | } | 244 | } |
209 | GNUNET_SCHEDULER_cancel (session->typemap_task); | 245 | if (GNUNET_SCHEDULER_NO_TASK != session->typemap_task) |
246 | { | ||
247 | GNUNET_SCHEDULER_cancel (session->typemap_task); | ||
248 | session->typemap_task = GNUNET_SCHEDULER_NO_TASK; | ||
249 | } | ||
210 | GSC_CLIENTS_notify_clients_about_neighbour (&session->peer, | 250 | GSC_CLIENTS_notify_clients_about_neighbour (&session->peer, |
211 | session->tmap, NULL); | 251 | session->tmap, NULL); |
212 | GNUNET_assert (GNUNET_YES == | 252 | GNUNET_assert (GNUNET_YES == |
@@ -224,7 +264,7 @@ GSC_SESSIONS_end (const struct GNUNET_PeerIdentity *pid) | |||
224 | 264 | ||
225 | /** | 265 | /** |
226 | * Transmit our current typemap message to the other peer. | 266 | * Transmit our current typemap message to the other peer. |
227 | * (Done periodically in case an update got lost). | 267 | * (Done periodically until the typemap is confirmed). |
228 | * | 268 | * |
229 | * @param cls the `struct Session *` | 269 | * @param cls the `struct Session *` |
230 | * @param tc unused | 270 | * @param tc unused |
@@ -237,20 +277,14 @@ transmit_typemap_task (void *cls, | |||
237 | struct GNUNET_MessageHeader *hdr; | 277 | struct GNUNET_MessageHeader *hdr; |
238 | struct GNUNET_TIME_Relative delay; | 278 | struct GNUNET_TIME_Relative delay; |
239 | 279 | ||
240 | if (0 == session->first_typemap) | 280 | session->typemap_delay = GNUNET_TIME_STD_BACKOFF (session->typemap_delay); |
241 | { | 281 | delay = session->typemap_delay; |
242 | delay = TYPEMAP_FREQUENCY_FIRST; | ||
243 | session->first_typemap = 1; | ||
244 | } | ||
245 | else | ||
246 | { | ||
247 | delay = TYPEMAP_FREQUENCY; | ||
248 | } | ||
249 | /* randomize a bit to avoid spont. sync */ | 282 | /* randomize a bit to avoid spont. sync */ |
250 | delay.rel_value_us += | 283 | delay.rel_value_us += |
251 | GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000 * 1000); | 284 | GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000 * 1000); |
252 | session->typemap_task = | 285 | session->typemap_task = |
253 | GNUNET_SCHEDULER_add_delayed (delay, &transmit_typemap_task, session); | 286 | GNUNET_SCHEDULER_add_delayed (delay, |
287 | &transmit_typemap_task, session); | ||
254 | GNUNET_STATISTICS_update (GSC_stats, | 288 | GNUNET_STATISTICS_update (GSC_stats, |
255 | gettext_noop ("# type map refreshes sent"), 1, | 289 | gettext_noop ("# type map refreshes sent"), 1, |
256 | GNUNET_NO); | 290 | GNUNET_NO); |
@@ -261,6 +295,24 @@ transmit_typemap_task (void *cls, | |||
261 | 295 | ||
262 | 296 | ||
263 | /** | 297 | /** |
298 | * Restart the typemap task for the given session. | ||
299 | * | ||
300 | * @param session session to restart typemap transmission for | ||
301 | */ | ||
302 | static void | ||
303 | start_typemap_task (struct Session *session) | ||
304 | { | ||
305 | if (GNUNET_SCHEDULER_NO_TASK != session->typemap_task) | ||
306 | GNUNET_SCHEDULER_cancel (session->typemap_task); | ||
307 | session->typemap_delay = GNUNET_TIME_UNIT_SECONDS; | ||
308 | session->typemap_task = | ||
309 | GNUNET_SCHEDULER_add_delayed (session->typemap_delay, | ||
310 | &transmit_typemap_task, | ||
311 | session); | ||
312 | } | ||
313 | |||
314 | |||
315 | /** | ||
264 | * Create a session, a key exchange was just completed. | 316 | * Create a session, a key exchange was just completed. |
265 | * | 317 | * |
266 | * @param peer peer that is now connected | 318 | * @param peer peer that is now connected |
@@ -279,10 +331,9 @@ GSC_SESSIONS_create (const struct GNUNET_PeerIdentity *peer, | |||
279 | session->tmap = GSC_TYPEMAP_create (); | 331 | session->tmap = GSC_TYPEMAP_create (); |
280 | session->peer = *peer; | 332 | session->peer = *peer; |
281 | session->kxinfo = kx; | 333 | session->kxinfo = kx; |
282 | session->typemap_task = | ||
283 | GNUNET_SCHEDULER_add_now (&transmit_typemap_task, session); | ||
284 | GNUNET_assert (GNUNET_OK == | 334 | GNUNET_assert (GNUNET_OK == |
285 | GNUNET_CONTAINER_multipeermap_put (sessions, peer, | 335 | GNUNET_CONTAINER_multipeermap_put (sessions, |
336 | &session->peer, | ||
286 | session, | 337 | session, |
287 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | 338 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); |
288 | GNUNET_STATISTICS_set (GSC_stats, gettext_noop ("# peers connected"), | 339 | GNUNET_STATISTICS_set (GSC_stats, gettext_noop ("# peers connected"), |
@@ -290,6 +341,79 @@ GSC_SESSIONS_create (const struct GNUNET_PeerIdentity *peer, | |||
290 | GNUNET_NO); | 341 | GNUNET_NO); |
291 | GSC_CLIENTS_notify_clients_about_neighbour (peer, | 342 | GSC_CLIENTS_notify_clients_about_neighbour (peer, |
292 | NULL, session->tmap); | 343 | NULL, session->tmap); |
344 | start_typemap_task (session); | ||
345 | } | ||
346 | |||
347 | |||
348 | /** | ||
349 | * The other peer has indicated that he 'lost' the session | ||
350 | * (KX down), reinitialize the session on our end, in particular | ||
351 | * this means to restart the typemap transmission. | ||
352 | * | ||
353 | * @param peer peer that is now connected | ||
354 | */ | ||
355 | void | ||
356 | GSC_SESSIONS_reinit (const struct GNUNET_PeerIdentity *peer) | ||
357 | { | ||
358 | struct Session *session; | ||
359 | |||
360 | session = find_session (peer); | ||
361 | if (NULL == session) | ||
362 | { | ||
363 | /* KX/session is new for both sides; thus no need to restart what | ||
364 | has not yet begun */ | ||
365 | return; | ||
366 | } | ||
367 | start_typemap_task (session); | ||
368 | } | ||
369 | |||
370 | |||
371 | /** | ||
372 | * The other peer has confirmed receiving our type map, | ||
373 | * check if it is current and if so, stop retransmitting it. | ||
374 | * | ||
375 | * @param peer peer that confirmed the type map | ||
376 | * @param msg confirmation message we received | ||
377 | */ | ||
378 | void | ||
379 | GSC_SESSIONS_confirm_typemap (const struct GNUNET_PeerIdentity *peer, | ||
380 | const struct GNUNET_MessageHeader *msg) | ||
381 | { | ||
382 | const struct TypeMapConfirmationMessage *cmsg; | ||
383 | struct Session *session; | ||
384 | |||
385 | session = find_session (peer); | ||
386 | if (NULL == session) | ||
387 | { | ||
388 | GNUNET_break (0); | ||
389 | return; | ||
390 | } | ||
391 | if (ntohs (msg->size) != sizeof (struct TypeMapConfirmationMessage)) | ||
392 | { | ||
393 | GNUNET_break_op (0); | ||
394 | return; | ||
395 | } | ||
396 | cmsg = (const struct TypeMapConfirmationMessage *) msg; | ||
397 | if (GNUNET_YES != | ||
398 | GSC_TYPEMAP_check_hash (&cmsg->tm_hash)) | ||
399 | { | ||
400 | /* our typemap has changed in the meantime, do not | ||
401 | accept confirmation */ | ||
402 | GNUNET_STATISTICS_update (GSC_stats, | ||
403 | gettext_noop | ||
404 | ("# outdated typemap confirmations received"), | ||
405 | 1, GNUNET_NO); | ||
406 | return; | ||
407 | } | ||
408 | if (GNUNET_SCHEDULER_NO_TASK != session->typemap_task) | ||
409 | { | ||
410 | GNUNET_SCHEDULER_cancel (session->typemap_task); | ||
411 | session->typemap_task = GNUNET_SCHEDULER_NO_TASK; | ||
412 | } | ||
413 | GNUNET_STATISTICS_update (GSC_stats, | ||
414 | gettext_noop | ||
415 | ("# valid typemap confirmations received"), | ||
416 | 1, GNUNET_NO); | ||
293 | } | 417 | } |
294 | 418 | ||
295 | 419 | ||
@@ -325,7 +449,8 @@ void | |||
325 | GSC_SESSIONS_notify_client_about_sessions (struct GSC_Client *client) | 449 | GSC_SESSIONS_notify_client_about_sessions (struct GSC_Client *client) |
326 | { | 450 | { |
327 | /* notify new client about existing sessions */ | 451 | /* notify new client about existing sessions */ |
328 | GNUNET_CONTAINER_multipeermap_iterate (sessions, ¬ify_client_about_session, | 452 | GNUNET_CONTAINER_multipeermap_iterate (sessions, |
453 | ¬ify_client_about_session, | ||
329 | client); | 454 | client); |
330 | } | 455 | } |
331 | 456 | ||
@@ -592,11 +717,14 @@ try_transmission (struct Session *session) | |||
592 | size_t used; | 717 | size_t used; |
593 | 718 | ||
594 | used = 0; | 719 | used = 0; |
595 | while ((NULL != (pos = session->sme_head)) && (used + pos->size <= msize)) | 720 | while ( (NULL != (pos = session->sme_head)) && |
721 | (used + pos->size <= msize) ) | ||
596 | { | 722 | { |
597 | memcpy (&pbuf[used], &pos[1], pos->size); | 723 | memcpy (&pbuf[used], &pos[1], pos->size); |
598 | used += pos->size; | 724 | used += pos->size; |
599 | GNUNET_CONTAINER_DLL_remove (session->sme_head, session->sme_tail, pos); | 725 | GNUNET_CONTAINER_DLL_remove (session->sme_head, |
726 | session->sme_tail, | ||
727 | pos); | ||
600 | GNUNET_free (pos); | 728 | GNUNET_free (pos); |
601 | } | 729 | } |
602 | /* compute average payload size */ | 730 | /* compute average payload size */ |
@@ -619,7 +747,8 @@ try_transmission (struct Session *session) | |||
619 | 747 | ||
620 | 748 | ||
621 | /** | 749 | /** |
622 | * Send a message to the neighbour now. | 750 | * Send an updated typemap message to the neighbour now, |
751 | * and restart typemap transmissions. | ||
623 | * | 752 | * |
624 | * @param cls the message | 753 | * @param cls the message |
625 | * @param key neighbour's identity | 754 | * @param key neighbour's identity |
@@ -627,38 +756,42 @@ try_transmission (struct Session *session) | |||
627 | * @return always #GNUNET_OK | 756 | * @return always #GNUNET_OK |
628 | */ | 757 | */ |
629 | static int | 758 | static int |
630 | do_send_message (void *cls, | 759 | do_restart_typemap_message (void *cls, |
631 | const struct GNUNET_PeerIdentity *key, | 760 | const struct GNUNET_PeerIdentity *key, |
632 | void *value) | 761 | void *value) |
633 | { | 762 | { |
634 | const struct GNUNET_MessageHeader *hdr = cls; | 763 | const struct GNUNET_MessageHeader *hdr = cls; |
635 | struct Session *session = value; | 764 | struct Session *session = value; |
636 | struct SessionMessageEntry *m; | 765 | struct SessionMessageEntry *sme; |
637 | uint16_t size; | 766 | uint16_t size; |
638 | 767 | ||
639 | size = ntohs (hdr->size); | 768 | size = ntohs (hdr->size); |
640 | m = GNUNET_malloc (sizeof (struct SessionMessageEntry) + size); | 769 | sme = GNUNET_malloc (sizeof (struct SessionMessageEntry) + size); |
641 | memcpy (&m[1], hdr, size); | 770 | memcpy (&sme[1], hdr, size); |
642 | m->size = size; | 771 | sme->size = size; |
643 | m->priority = GNUNET_CORE_PRIO_CRITICAL_CONTROL; | 772 | sme->priority = GNUNET_CORE_PRIO_CRITICAL_CONTROL; |
644 | GNUNET_CONTAINER_DLL_insert_tail (session->sme_head, session->sme_tail, m); | 773 | GNUNET_CONTAINER_DLL_insert (session->sme_head, |
774 | session->sme_tail, | ||
775 | sme); | ||
645 | try_transmission (session); | 776 | try_transmission (session); |
777 | start_typemap_task (session); | ||
646 | return GNUNET_OK; | 778 | return GNUNET_OK; |
647 | } | 779 | } |
648 | 780 | ||
649 | 781 | ||
650 | /** | 782 | /** |
651 | * Broadcast a message to all neighbours. | 783 | * Broadcast an updated typemap message to all neighbours. |
784 | * Restarts the retransmissions until the typemaps are confirmed. | ||
652 | * | 785 | * |
653 | * @param msg message to transmit | 786 | * @param msg message to transmit |
654 | */ | 787 | */ |
655 | void | 788 | void |
656 | GSC_SESSIONS_broadcast (const struct GNUNET_MessageHeader *msg) | 789 | GSC_SESSIONS_broadcast_typemap (const struct GNUNET_MessageHeader *msg) |
657 | { | 790 | { |
658 | if (NULL == sessions) | 791 | if (NULL == sessions) |
659 | return; | 792 | return; |
660 | GNUNET_CONTAINER_multipeermap_iterate (sessions, | 793 | GNUNET_CONTAINER_multipeermap_iterate (sessions, |
661 | &do_send_message, | 794 | &do_restart_typemap_message, |
662 | (void *) msg); | 795 | (void *) msg); |
663 | } | 796 | } |
664 | 797 | ||
@@ -732,7 +865,7 @@ GSC_SESSIONS_transmit (struct GSC_ClientActiveRequest *car, | |||
732 | 865 | ||
733 | 866 | ||
734 | /** | 867 | /** |
735 | * We've received a typemap message from a peer, update ours. | 868 | * We have received a typemap message from a peer, update ours. |
736 | * Notifies clients about the session. | 869 | * Notifies clients about the session. |
737 | * | 870 | * |
738 | * @param peer peer this is about | 871 | * @param peer peer this is about |
@@ -744,6 +877,8 @@ GSC_SESSIONS_set_typemap (const struct GNUNET_PeerIdentity *peer, | |||
744 | { | 877 | { |
745 | struct Session *session; | 878 | struct Session *session; |
746 | struct GSC_TypeMap *nmap; | 879 | struct GSC_TypeMap *nmap; |
880 | struct SessionMessageEntry *sme; | ||
881 | struct TypeMapConfirmationMessage *tmc; | ||
747 | 882 | ||
748 | nmap = GSC_TYPEMAP_get_from_message (msg); | 883 | nmap = GSC_TYPEMAP_get_from_message (msg); |
749 | if (NULL == nmap) | 884 | if (NULL == nmap) |
@@ -754,8 +889,24 @@ GSC_SESSIONS_set_typemap (const struct GNUNET_PeerIdentity *peer, | |||
754 | GNUNET_break (0); | 889 | GNUNET_break (0); |
755 | return; | 890 | return; |
756 | } | 891 | } |
892 | sme = GNUNET_malloc (sizeof (struct SessionMessageEntry) + | ||
893 | sizeof (struct TypeMapConfirmationMessage)); | ||
894 | sme->deadline = GNUNET_TIME_absolute_get (); | ||
895 | sme->size = sizeof (struct TypeMapConfirmationMessage); | ||
896 | sme->priority = GNUNET_CORE_PRIO_CRITICAL_CONTROL; | ||
897 | tmc = (struct TypeMapConfirmationMessage *) &sme[1]; | ||
898 | tmc->header.size = htons (sizeof (struct TypeMapConfirmationMessage)); | ||
899 | tmc->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_CONFIRM_TYPE_MAP); | ||
900 | tmc->reserved = htonl (0); | ||
901 | GSC_TYPEMAP_hash (nmap, | ||
902 | &tmc->tm_hash); | ||
903 | GNUNET_CONTAINER_DLL_insert (session->sme_head, | ||
904 | session->sme_tail, | ||
905 | sme); | ||
906 | try_transmission (session); | ||
757 | GSC_CLIENTS_notify_clients_about_neighbour (peer, | 907 | GSC_CLIENTS_notify_clients_about_neighbour (peer, |
758 | session->tmap, nmap); | 908 | session->tmap, |
909 | nmap); | ||
759 | GSC_TYPEMAP_destroy (session->tmap); | 910 | GSC_TYPEMAP_destroy (session->tmap); |
760 | session->tmap = nmap; | 911 | session->tmap = nmap; |
761 | } | 912 | } |
@@ -776,7 +927,9 @@ GSC_SESSIONS_add_to_typemap (const struct GNUNET_PeerIdentity *peer, | |||
776 | struct Session *session; | 927 | struct Session *session; |
777 | struct GSC_TypeMap *nmap; | 928 | struct GSC_TypeMap *nmap; |
778 | 929 | ||
779 | if (0 == memcmp (peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity))) | 930 | if (0 == memcmp (peer, |
931 | &GSC_my_identity, | ||
932 | sizeof (struct GNUNET_PeerIdentity))) | ||
780 | return; | 933 | return; |
781 | session = find_session (peer); | 934 | session = find_session (peer); |
782 | GNUNET_assert (NULL != session); | 935 | GNUNET_assert (NULL != session); |
@@ -796,12 +949,14 @@ GSC_SESSIONS_add_to_typemap (const struct GNUNET_PeerIdentity *peer, | |||
796 | void | 949 | void |
797 | GSC_SESSIONS_init () | 950 | GSC_SESSIONS_init () |
798 | { | 951 | { |
799 | sessions = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO); | 952 | sessions = GNUNET_CONTAINER_multipeermap_create (128, |
953 | GNUNET_YES); | ||
800 | } | 954 | } |
801 | 955 | ||
802 | 956 | ||
803 | /** | 957 | /** |
804 | * Helper function for GSC_SESSIONS_handle_client_iterate_peers. | 958 | * Helper function for #GSC_SESSIONS_done() to free all |
959 | * active sessions. | ||
805 | * | 960 | * |
806 | * @param cls NULL | 961 | * @param cls NULL |
807 | * @param key identity of the connected peer | 962 | * @param key identity of the connected peer |
@@ -828,7 +983,8 @@ GSC_SESSIONS_done () | |||
828 | { | 983 | { |
829 | if (NULL != sessions) | 984 | if (NULL != sessions) |
830 | { | 985 | { |
831 | GNUNET_CONTAINER_multipeermap_iterate (sessions, &free_session_helper, NULL); | 986 | GNUNET_CONTAINER_multipeermap_iterate (sessions, |
987 | &free_session_helper, NULL); | ||
832 | GNUNET_CONTAINER_multipeermap_destroy (sessions); | 988 | GNUNET_CONTAINER_multipeermap_destroy (sessions); |
833 | sessions = NULL; | 989 | sessions = NULL; |
834 | } | 990 | } |