#include "gnunet-service-core_sessions.h"
#include "gnunet-service-core_clients.h"
#include "gnunet_constants.h"
-
-/**
- * How often do we transmit our typemap?
- */
-#define TYPEMAP_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
-
-/**
- * How often do we transmit our typemap on first attempt?
- */
-#define TYPEMAP_FREQUENCY_FIRST GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
+#include "core.h"
/**
*/
GNUNET_SCHEDULER_TaskIdentifier typemap_task;
+ /**
+ * Retransmission delay we currently use for the typemap
+ * transmissions (if not confirmed).
+ */
+ struct GNUNET_TIME_Relative typemap_delay;
+
/**
* Is the neighbour queue empty and thus ready for us
* to transmit an encrypted message?
};
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * Message sent to confirm that a typemap was received.
+ */
+struct TypeMapConfirmationMessage
+{
+
+ /**
+ * Header with type #GNUNET_MESSAGE_TYPE_CORE_CONFIRM_TYPE_MAP.
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Reserved, always zero.
+ */
+ uint32_t reserved GNUNET_PACKED;
+
+ /**
+ * Hash of the (decompressed) type map that was received.
+ */
+ struct GNUNET_HashCode tm_hash;
+
+};
+
+GNUNET_NETWORK_STRUCT_END
+
+
/**
* Map of peer identities to `struct Session`.
*/
}
while (NULL != (sme = session->sme_head))
{
- GNUNET_CONTAINER_DLL_remove (session->sme_head, session->sme_tail, sme);
+ GNUNET_CONTAINER_DLL_remove (session->sme_head,
+ session->sme_tail,
+ sme);
GNUNET_free (sme);
}
- GNUNET_SCHEDULER_cancel (session->typemap_task);
+ if (GNUNET_SCHEDULER_NO_TASK != session->typemap_task)
+ {
+ GNUNET_SCHEDULER_cancel (session->typemap_task);
+ session->typemap_task = GNUNET_SCHEDULER_NO_TASK;
+ }
GSC_CLIENTS_notify_clients_about_neighbour (&session->peer,
session->tmap, NULL);
GNUNET_assert (GNUNET_YES ==
/**
* Transmit our current typemap message to the other peer.
- * (Done periodically in case an update got lost).
+ * (Done periodically until the typemap is confirmed).
*
* @param cls the `struct Session *`
* @param tc unused
struct GNUNET_MessageHeader *hdr;
struct GNUNET_TIME_Relative delay;
- if (0 == session->first_typemap)
- {
- delay = TYPEMAP_FREQUENCY_FIRST;
- session->first_typemap = 1;
- }
- else
- {
- delay = TYPEMAP_FREQUENCY;
- }
+ session->typemap_delay = GNUNET_TIME_STD_BACKOFF (session->typemap_delay);
+ delay = session->typemap_delay;
/* randomize a bit to avoid spont. sync */
delay.rel_value_us +=
GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000 * 1000);
session->typemap_task =
- GNUNET_SCHEDULER_add_delayed (delay, &transmit_typemap_task, session);
+ GNUNET_SCHEDULER_add_delayed (delay,
+ &transmit_typemap_task, session);
GNUNET_STATISTICS_update (GSC_stats,
gettext_noop ("# type map refreshes sent"), 1,
GNUNET_NO);
}
+/**
+ * Restart the typemap task for the given session.
+ *
+ * @param session session to restart typemap transmission for
+ */
+static void
+start_typemap_task (struct Session *session)
+{
+ if (GNUNET_SCHEDULER_NO_TASK != session->typemap_task)
+ GNUNET_SCHEDULER_cancel (session->typemap_task);
+ session->typemap_delay = GNUNET_TIME_UNIT_SECONDS;
+ session->typemap_task =
+ GNUNET_SCHEDULER_add_delayed (session->typemap_delay,
+ &transmit_typemap_task,
+ session);
+}
+
+
/**
* Create a session, a key exchange was just completed.
*
session->tmap = GSC_TYPEMAP_create ();
session->peer = *peer;
session->kxinfo = kx;
- session->typemap_task =
- GNUNET_SCHEDULER_add_now (&transmit_typemap_task, session);
GNUNET_assert (GNUNET_OK ==
- GNUNET_CONTAINER_multipeermap_put (sessions, peer,
+ GNUNET_CONTAINER_multipeermap_put (sessions,
+ &session->peer,
session,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
GNUNET_STATISTICS_set (GSC_stats, gettext_noop ("# peers connected"),
GNUNET_CONTAINER_multipeermap_size (sessions),
GNUNET_NO);
GSC_CLIENTS_notify_clients_about_neighbour (peer,
- NULL, session->tmap);
+ NULL,
+ session->tmap);
+ start_typemap_task (session);
+}
+
+
+/**
+ * The other peer has indicated that he 'lost' the session
+ * (KX down), reinitialize the session on our end, in particular
+ * this means to restart the typemap transmission.
+ *
+ * @param peer peer that is now connected
+ */
+void
+GSC_SESSIONS_reinit (const struct GNUNET_PeerIdentity *peer)
+{
+ struct Session *session;
+
+ session = find_session (peer);
+ if (NULL == session)
+ {
+ /* KX/session is new for both sides; thus no need to restart what
+ has not yet begun */
+ return;
+ }
+ start_typemap_task (session);
+}
+
+
+/**
+ * The other peer has confirmed receiving our type map,
+ * check if it is current and if so, stop retransmitting it.
+ *
+ * @param peer peer that confirmed the type map
+ * @param msg confirmation message we received
+ */
+void
+GSC_SESSIONS_confirm_typemap (const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *msg)
+{
+ const struct TypeMapConfirmationMessage *cmsg;
+ struct Session *session;
+
+ session = find_session (peer);
+ if (NULL == session)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ if (ntohs (msg->size) != sizeof (struct TypeMapConfirmationMessage))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ cmsg = (const struct TypeMapConfirmationMessage *) msg;
+ if (GNUNET_YES !=
+ GSC_TYPEMAP_check_hash (&cmsg->tm_hash))
+ {
+ /* our typemap has changed in the meantime, do not
+ accept confirmation */
+ GNUNET_STATISTICS_update (GSC_stats,
+ gettext_noop
+ ("# outdated typemap confirmations received"),
+ 1, GNUNET_NO);
+ return;
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != session->typemap_task)
+ {
+ GNUNET_SCHEDULER_cancel (session->typemap_task);
+ session->typemap_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ GNUNET_STATISTICS_update (GSC_stats,
+ gettext_noop
+ ("# valid typemap confirmations received"),
+ 1, GNUNET_NO);
}
struct GSC_Client *client = cls;
struct Session *session = value;
- GSC_CLIENTS_notify_client_about_neighbour (client, &session->peer,
+ GSC_CLIENTS_notify_client_about_neighbour (client,
+ &session->peer,
NULL, /* old TMAP: none */
session->tmap);
return GNUNET_OK;
GSC_SESSIONS_notify_client_about_sessions (struct GSC_Client *client)
{
/* notify new client about existing sessions */
- GNUNET_CONTAINER_multipeermap_iterate (sessions, ¬ify_client_about_session,
+ GNUNET_CONTAINER_multipeermap_iterate (sessions,
+ ¬ify_client_about_session,
client);
}
void
GSC_SESSIONS_dequeue_request (struct GSC_ClientActiveRequest *car)
{
- struct Session *s;
+ struct Session *session;
if (0 ==
memcmp (&car->target, &GSC_my_identity,
sizeof (struct GNUNET_PeerIdentity)))
return;
- s = find_session (&car->target);
- GNUNET_assert (NULL != s);
- GNUNET_CONTAINER_DLL_remove (s->active_client_request_head,
- s->active_client_request_tail, car);
+ session = find_session (&car->target);
+ GNUNET_assert (NULL != session);
+ GNUNET_CONTAINER_DLL_remove (session->active_client_request_head,
+ session->active_client_request_tail,
+ car);
}
return;
}
}
-
+ else
+ {
+ /* never solicit more, we have critical messages to process */
+ excess = GNUNET_NO;
+ maxpc = GNUNET_CORE_PRIO_BACKGROUND;
+ }
now = GNUNET_TIME_absolute_get ();
if ( ( (GNUNET_YES == excess) ||
(maxpc >= GNUNET_CORE_PRIO_BEST_EFFORT) ) &&
size_t used;
used = 0;
- while ((NULL != (pos = session->sme_head)) && (used + pos->size <= msize))
+ while ( (NULL != (pos = session->sme_head)) &&
+ (used + pos->size <= msize) )
{
memcpy (&pbuf[used], &pos[1], pos->size);
used += pos->size;
- GNUNET_CONTAINER_DLL_remove (session->sme_head, session->sme_tail, pos);
+ GNUNET_CONTAINER_DLL_remove (session->sme_head,
+ session->sme_tail,
+ pos);
GNUNET_free (pos);
}
/* compute average payload size */
/**
- * Send a message to the neighbour now.
+ * Send an updated typemap message to the neighbour now,
+ * and restart typemap transmissions.
*
* @param cls the message
* @param key neighbour's identity
* @return always #GNUNET_OK
*/
static int
-do_send_message (void *cls,
- const struct GNUNET_PeerIdentity *key,
- void *value)
+do_restart_typemap_message (void *cls,
+ const struct GNUNET_PeerIdentity *key,
+ void *value)
{
const struct GNUNET_MessageHeader *hdr = cls;
struct Session *session = value;
- struct SessionMessageEntry *m;
+ struct SessionMessageEntry *sme;
uint16_t size;
size = ntohs (hdr->size);
- m = GNUNET_malloc (sizeof (struct SessionMessageEntry) + size);
- memcpy (&m[1], hdr, size);
- m->size = size;
- m->priority = GNUNET_CORE_PRIO_CRITICAL_CONTROL;
- GNUNET_CONTAINER_DLL_insert_tail (session->sme_head, session->sme_tail, m);
+ sme = GNUNET_malloc (sizeof (struct SessionMessageEntry) + size);
+ memcpy (&sme[1], hdr, size);
+ sme->size = size;
+ sme->priority = GNUNET_CORE_PRIO_CRITICAL_CONTROL;
+ GNUNET_CONTAINER_DLL_insert (session->sme_head,
+ session->sme_tail,
+ sme);
try_transmission (session);
+ start_typemap_task (session);
return GNUNET_OK;
}
/**
- * Broadcast a message to all neighbours.
+ * Broadcast an updated typemap message to all neighbours.
+ * Restarts the retransmissions until the typemaps are confirmed.
*
* @param msg message to transmit
*/
void
-GSC_SESSIONS_broadcast (const struct GNUNET_MessageHeader *msg)
+GSC_SESSIONS_broadcast_typemap (const struct GNUNET_MessageHeader *msg)
{
if (NULL == sessions)
return;
GNUNET_CONTAINER_multipeermap_iterate (sessions,
- &do_send_message,
+ &do_restart_typemap_message,
(void *) msg);
}
/**
- * Helper function for GSC_SESSIONS_handle_client_iterate_peers.
- *
- * @param cls the `struct GNUNET_SERVER_TransmitContext` to queue replies
- * @param key identity of the connected peer
- * @param value the `struct Neighbour` for the peer
- * @return GNUNET_OK (continue to iterate)
- */
-#include "core.h"
-static int
-queue_connect_message (void *cls,
- const struct GNUNET_PeerIdentity *key,
- void *value)
-{
- struct GNUNET_SERVER_TransmitContext *tc = cls;
- struct Session *session = value;
- struct ConnectNotifyMessage cnm;
-
- /* FIXME: code duplication with clients... */
- cnm.header.size = htons (sizeof (struct ConnectNotifyMessage));
- cnm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
- cnm.reserved = htonl (0);
- cnm.peer = session->peer;
- GNUNET_SERVER_transmit_context_append_message (tc, &cnm.header);
- return GNUNET_OK;
-}
-
-
-/**
- * Handle CORE_ITERATE_PEERS request. For this request type, the client
- * does not have to have transmitted an INIT request. All current peers
- * are returned, regardless of which message types they accept.
- *
- * @param cls unused
- * @param client client sending the iteration request
- * @param message iteration request message
- */
-void
-GSC_SESSIONS_handle_client_iterate_peers (void *cls,
- struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader
- *message)
-{
- struct GNUNET_MessageHeader done_msg;
- struct GNUNET_SERVER_TransmitContext *tc;
-
- tc = GNUNET_SERVER_transmit_context_create (client);
- GNUNET_CONTAINER_multipeermap_iterate (sessions, &queue_connect_message, tc);
- done_msg.size = htons (sizeof (struct GNUNET_MessageHeader));
- done_msg.type = htons (GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END);
- GNUNET_SERVER_transmit_context_append_message (tc, &done_msg);
- GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
-}
-
-
-/**
- * We've received a typemap message from a peer, update ours.
+ * We have received a typemap message from a peer, update ours.
* Notifies clients about the session.
*
* @param peer peer this is about
{
struct Session *session;
struct GSC_TypeMap *nmap;
+ struct SessionMessageEntry *sme;
+ struct TypeMapConfirmationMessage *tmc;
nmap = GSC_TYPEMAP_get_from_message (msg);
if (NULL == nmap)
GNUNET_break (0);
return;
}
+ sme = GNUNET_malloc (sizeof (struct SessionMessageEntry) +
+ sizeof (struct TypeMapConfirmationMessage));
+ sme->deadline = GNUNET_TIME_absolute_get ();
+ sme->size = sizeof (struct TypeMapConfirmationMessage);
+ sme->priority = GNUNET_CORE_PRIO_CRITICAL_CONTROL;
+ tmc = (struct TypeMapConfirmationMessage *) &sme[1];
+ tmc->header.size = htons (sizeof (struct TypeMapConfirmationMessage));
+ tmc->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_CONFIRM_TYPE_MAP);
+ tmc->reserved = htonl (0);
+ GSC_TYPEMAP_hash (nmap,
+ &tmc->tm_hash);
+ GNUNET_CONTAINER_DLL_insert (session->sme_head,
+ session->sme_tail,
+ sme);
+ try_transmission (session);
GSC_CLIENTS_notify_clients_about_neighbour (peer,
- session->tmap, nmap);
+ session->tmap,
+ nmap);
GSC_TYPEMAP_destroy (session->tmap);
session->tmap = nmap;
}
struct Session *session;
struct GSC_TypeMap *nmap;
- if (0 == memcmp (peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity)))
+ if (0 == memcmp (peer,
+ &GSC_my_identity,
+ sizeof (struct GNUNET_PeerIdentity)))
return;
session = find_session (peer);
GNUNET_assert (NULL != session);
void
GSC_SESSIONS_init ()
{
- sessions = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
+ sessions = GNUNET_CONTAINER_multipeermap_create (128,
+ GNUNET_YES);
}
/**
- * Helper function for GSC_SESSIONS_handle_client_iterate_peers.
+ * Helper function for #GSC_SESSIONS_done() to free all
+ * active sessions.
*
* @param cls NULL
* @param key identity of the connected peer
{
if (NULL != sessions)
{
- GNUNET_CONTAINER_multipeermap_iterate (sessions, &free_session_helper, NULL);
+ GNUNET_CONTAINER_multipeermap_iterate (sessions,
+ &free_session_helper, NULL);
GNUNET_CONTAINER_multipeermap_destroy (sessions);
sessions = NULL;
}