aboutsummaryrefslogtreecommitdiff
path: root/src/core/gnunet-service-core_sessions.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2014-04-23 11:04:53 +0000
committerChristian Grothoff <christian@grothoff.org>2014-04-23 11:04:53 +0000
commita19683a4b76e10843c4e75db928bac5750c6430a (patch)
tree7aeff0c4d49b5f3750c569216e77912016fd5a81 /src/core/gnunet-service-core_sessions.c
parent21bac846638fbbbe2b03672295d4f14fc3ceb839 (diff)
downloadgnunet-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.c232
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
160GNUNET_NETWORK_STRUCT_BEGIN
161
162/**
163 * Message sent to confirm that a typemap was received.
164 */
165struct 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
185GNUNET_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 */
302static void
303start_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 */
355void
356GSC_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 */
378void
379GSC_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
325GSC_SESSIONS_notify_client_about_sessions (struct GSC_Client *client) 449GSC_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, &notify_client_about_session, 452 GNUNET_CONTAINER_multipeermap_iterate (sessions,
453 &notify_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 */
629static int 758static int
630do_send_message (void *cls, 759do_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 */
655void 788void
656GSC_SESSIONS_broadcast (const struct GNUNET_MessageHeader *msg) 789GSC_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,
796void 949void
797GSC_SESSIONS_init () 950GSC_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 }