[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] r17242 - gnunet/src/core
From: |
gnunet |
Subject: |
[GNUnet-SVN] r17242 - gnunet/src/core |
Date: |
Thu, 6 Oct 2011 13:01:23 +0200 |
Author: grothoff
Date: 2011-10-06 13:01:23 +0200 (Thu, 06 Oct 2011)
New Revision: 17242
Added:
gnunet/src/core/gnunet-service-core_clients.h
gnunet/src/core/gnunet-service-core_neighbours.h
Removed:
gnunet/src/core/gnunet-service-core_crypto.c
gnunet/src/core/gnunet-service-core_plan.c
Modified:
gnunet/src/core/Makefile.am
gnunet/src/core/gnunet-service-core-new.c
gnunet/src/core/gnunet-service-core_clients.c
gnunet/src/core/gnunet-service-core_kx.c
gnunet/src/core/gnunet-service-core_kx.h
gnunet/src/core/gnunet-service-core_neighbours.c
gnunet/src/core/gnunet-service-core_sessions.c
gnunet/src/core/gnunet-service-core_typemap.c
Log:
hxing
Modified: gnunet/src/core/Makefile.am
===================================================================
--- gnunet/src/core/Makefile.am 2011-10-06 09:02:48 UTC (rev 17241)
+++ gnunet/src/core/Makefile.am 2011-10-06 11:01:23 UTC (rev 17242)
@@ -39,7 +39,11 @@
$(GN_LIBINTL) -lz
gnunet_service_core_new_SOURCES = \
- gnunet-service-core-new.c
+ gnunet-service-core-new.c gnunet-service-core.h \
+ gnunet-service-core_clients.c gnunet-service-core_clients.h \
+ gnunet-service-core_neighbours.c gnunet-service-core_neighbours.h \
+ gnunet-service-core_kx.c gnunet-service-core_kx.h \
+ gnunet-service-core_sessions.c gnunet-service-core_sessions.h
gnunet_service_core_new_LDADD = \
$(top_builddir)/src/hello/libgnunethello.la \
$(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
Modified: gnunet/src/core/gnunet-service-core-new.c
===================================================================
--- gnunet/src/core/gnunet-service-core-new.c 2011-10-06 09:02:48 UTC (rev
17241)
+++ gnunet/src/core/gnunet-service-core-new.c 2011-10-06 11:01:23 UTC (rev
17242)
@@ -177,53 +177,7 @@
PEER_STATE_KEY_CONFIRMED
};
-
/**
- * Encapsulation for encrypted messages exchanged between
- * peers. Followed by the actual encrypted data.
- */
-struct EncryptedMessage
-{
- /**
- * Message type is either CORE_ENCRYPTED_MESSAGE.
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * Random value used for IV generation.
- */
- uint32_t iv_seed GNUNET_PACKED;
-
- /**
- * MAC of the encrypted message (starting at 'sequence_number'),
- * used to verify message integrity. Everything after this value
- * (excluding this value itself) will be encrypted and authenticated.
- * ENCRYPTED_HEADER_SIZE must be set to the offset of the *next* field.
- */
- GNUNET_HashCode hmac;
-
- /**
- * Sequence number, in network byte order. This field
- * must be the first encrypted/decrypted field
- */
- uint32_t sequence_number GNUNET_PACKED;
-
- /**
- * Desired bandwidth (how much we should send to this peer / how
- * much is the sender willing to receive)?
- */
- struct GNUNET_BANDWIDTH_Value32NBO inbound_bw_limit;
-
- /**
- * Timestamp. Used to prevent reply of ancient messages
- * (recent messages are caught with the sequence number).
- */
- struct GNUNET_TIME_AbsoluteNBO timestamp;
-
-};
-
-
-/**
* Number of bytes (at the beginning) of "struct EncryptedMessage"
* that are NOT encrypted.
*/
Modified: gnunet/src/core/gnunet-service-core_clients.c
===================================================================
--- gnunet/src/core/gnunet-service-core_clients.c 2011-10-06 09:02:48 UTC
(rev 17241)
+++ gnunet/src/core/gnunet-service-core_clients.c 2011-10-06 11:01:23 UTC
(rev 17242)
@@ -1,5 +1,37 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
/**
+ * @file core/gnunet-service-core_clients.c
+ * @brief code for managing interactions with clients of core service
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_transport_service.h"
+#include "gnunet_service_core.h"
+#include "gnunet_service_core_clients.h"
+#include "gnunet_service_core_sessions.h"
+
+
+/**
* Data structure for each client connected to the core service.
*/
struct Client
@@ -923,12 +955,12 @@
/**
* Deliver P2P message to interested clients.
*
- * @param cls always NULL
- * @param client who sent us the message (struct Neighbour)
+ * @param sender peer who sent us the message
* @param m the message
*/
-static void
-deliver_message (void *cls, void *client, const struct GNUNET_MessageHeader *m)
+void
+GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
+ const struct GNUNET_MessageHeader *m)
{
struct Neighbour *sender = client;
size_t msize = ntohs (m->size);
Added: gnunet/src/core/gnunet-service-core_clients.h
===================================================================
--- gnunet/src/core/gnunet-service-core_clients.h
(rev 0)
+++ gnunet/src/core/gnunet-service-core_clients.h 2011-10-06 11:01:23 UTC
(rev 17242)
@@ -0,0 +1,71 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file core/gnunet-service-core_clients.h
+ * @brief code for managing interactions with clients of core service
+ * @author Christian Grothoff
+ */
+#include "gnunet_util_lib.h"
+#include "gnunet_service_core_clients.h"
+
+#ifndef GNUNET_SERVICE_CORE_CLIENTS_H
+#define GNUNET_SERVICE_CORE_CLIENTS_H
+
+
+/**
+ * Notify client about a change to existing connection to one of our
neighbours.
+ *
+ * @param neighbour identity of the neighbour that changed status
+ * @param tmap updated type map for the neighbour, NULL for disconnect
+ */
+void
+GDS_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity
*neighbour,
+ const struct GSC_TypeMap *tmap);
+
+
+/**
+ * Deliver P2P message to interested clients.
+ *
+ * @param sender peer who sent us the message
+ * @param m the message
+ */
+void
+GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
+ const struct GNUNET_MessageHeader *m);
+
+
+/**
+ * Initialize clients subsystem.
+ *
+ * @param server handle to server clients connect to
+ */
+void
+GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server);
+
+
+/**
+ * Shutdown clients subsystem.
+ */
+void
+GSC_CLIENTS_done (void);
+
+#endif
+/* end of gnunet-service-core_clients.h */
Deleted: gnunet/src/core/gnunet-service-core_crypto.c
===================================================================
--- gnunet/src/core/gnunet-service-core_crypto.c 2011-10-06 09:02:48 UTC
(rev 17241)
+++ gnunet/src/core/gnunet-service-core_crypto.c 2011-10-06 11:01:23 UTC
(rev 17242)
@@ -1,361 +0,0 @@
-
-/**
- * Our private key.
- */
-static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
-
-/**
- * Our public key.
- */
-static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
-
-
-/**
- * Derive an authentication key from "set key" information
- */
-static void
-derive_auth_key (struct GNUNET_CRYPTO_AuthKey *akey,
- const struct GNUNET_CRYPTO_AesSessionKey *skey, uint32_t seed,
- struct GNUNET_TIME_Absolute creation_time)
-{
- static const char ctx[] = "authentication key";
- struct GNUNET_TIME_AbsoluteNBO ctbe;
-
-
- ctbe = GNUNET_TIME_absolute_hton (creation_time);
- GNUNET_CRYPTO_hmac_derive_key (akey, skey, &seed, sizeof (seed), &skey->key,
- sizeof (skey->key), &ctbe, sizeof (ctbe), ctx,
- sizeof (ctx), NULL);
-}
-
-
-/**
- * Derive an IV from packet information
- */
-static void
-derive_iv (struct GNUNET_CRYPTO_AesInitializationVector *iv,
- const struct GNUNET_CRYPTO_AesSessionKey *skey, uint32_t seed,
- const struct GNUNET_PeerIdentity *identity)
-{
- static const char ctx[] = "initialization vector";
-
- GNUNET_CRYPTO_aes_derive_iv (iv, skey, &seed, sizeof (seed),
- &identity->hashPubKey.bits,
- sizeof (identity->hashPubKey.bits), ctx,
- sizeof (ctx), NULL);
-}
-
-/**
- * Derive an IV from pong packet information
- */
-static void
-derive_pong_iv (struct GNUNET_CRYPTO_AesInitializationVector *iv,
- const struct GNUNET_CRYPTO_AesSessionKey *skey, uint32_t seed,
- uint32_t challenge, const struct GNUNET_PeerIdentity *identity)
-{
- static const char ctx[] = "pong initialization vector";
-
- GNUNET_CRYPTO_aes_derive_iv (iv, skey, &seed, sizeof (seed),
- &identity->hashPubKey.bits,
- sizeof (identity->hashPubKey.bits), &challenge,
- sizeof (challenge), ctx, sizeof (ctx), NULL);
-}
-
-
-/**
- * Encrypt size bytes from in and write the result to out. Use the
- * key for outbound traffic of the given neighbour.
- *
- * @param n neighbour we are sending to
- * @param iv initialization vector to use
- * @param in ciphertext
- * @param out plaintext
- * @param size size of in/out
- * @return GNUNET_OK on success
- */
-static int
-do_encrypt (struct Neighbour *n,
- const struct GNUNET_CRYPTO_AesInitializationVector *iv,
- const void *in, void *out, size_t size)
-{
- if (size != (uint16_t) size)
- {
- GNUNET_break (0);
- return GNUNET_NO;
- }
- GNUNET_assert (size ==
- GNUNET_CRYPTO_aes_encrypt (in, (uint16_t) size,
- &n->encrypt_key, iv, out));
- GNUNET_STATISTICS_update (stats, gettext_noop ("# bytes encrypted"), size,
- GNUNET_NO);
-#if DEBUG_CORE > 2
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Encrypted %u bytes for `%4s' using key %u, IV %u\n",
- (unsigned int) size, GNUNET_i2s (&n->peer),
- (unsigned int) n->encrypt_key.crc32, GNUNET_CRYPTO_crc32_n (iv,
-
sizeof
-
(iv)));
-#endif
- return GNUNET_OK;
-}
-
-
-
-
-/**
- * Decrypt size bytes from in and write the result to out. Use the
- * key for inbound traffic of the given neighbour. This function does
- * NOT do any integrity-checks on the result.
- *
- * @param n neighbour we are receiving from
- * @param iv initialization vector to use
- * @param in ciphertext
- * @param out plaintext
- * @param size size of in/out
- * @return GNUNET_OK on success
- */
-static int
-do_decrypt (struct Neighbour *n,
- const struct GNUNET_CRYPTO_AesInitializationVector *iv,
- const void *in, void *out, size_t size)
-{
- if (size != (uint16_t) size)
- {
- GNUNET_break (0);
- return GNUNET_NO;
- }
- if ((n->status != PEER_STATE_KEY_RECEIVED) &&
- (n->status != PEER_STATE_KEY_CONFIRMED))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (size !=
- GNUNET_CRYPTO_aes_decrypt (in, (uint16_t) size, &n->decrypt_key, iv,
out))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- GNUNET_STATISTICS_update (stats, gettext_noop ("# bytes decrypted"), size,
- GNUNET_NO);
-#if DEBUG_CORE > 1
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Decrypted %u bytes from `%4s' using key %u, IV %u\n",
- (unsigned int) size, GNUNET_i2s (&n->peer),
- (unsigned int) n->decrypt_key.crc32, GNUNET_CRYPTO_crc32_n (iv,
-
sizeof
-
(*iv)));
-#endif
- return GNUNET_OK;
-}
-
-
-
-/**
- * We received an encrypted message. Decrypt, validate and
- * pass on to the appropriate clients.
- *
- * @param n target of the message
- * @param m encrypted message
- * @param ats performance data
- * @param ats_count number of entries in ats (excluding 0-termination)
- */
-static void
-handle_encrypted_message (struct Neighbour *n, const struct EncryptedMessage
*m,
- const struct GNUNET_TRANSPORT_ATS_Information *ats,
- uint32_t ats_count)
-{
- size_t size = ntohs (m->header.size);
- char buf[size];
- struct EncryptedMessage *pt; /* plaintext */
- GNUNET_HashCode ph;
- uint32_t snum;
- struct GNUNET_TIME_Absolute t;
- struct GNUNET_CRYPTO_AesInitializationVector iv;
- struct GNUNET_CRYPTO_AuthKey auth_key;
-
-#if DEBUG_CORE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Core service receives `%s' request from `%4s'.\n",
- "ENCRYPTED_MESSAGE", GNUNET_i2s (&n->peer));
-#endif
- /* validate hash */
- derive_auth_key (&auth_key, &n->decrypt_key, m->iv_seed,
- n->decrypt_key_created);
- GNUNET_CRYPTO_hmac (&auth_key, &m->sequence_number,
- size - ENCRYPTED_HEADER_SIZE, &ph);
-#if DEBUG_HANDSHAKE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Re-Authenticated %u bytes of ciphertext (`%u'): `%s'\n",
- (unsigned int) size - ENCRYPTED_HEADER_SIZE,
- GNUNET_CRYPTO_crc32_n (&m->sequence_number,
- size - ENCRYPTED_HEADER_SIZE),
- GNUNET_h2s (&ph));
-#endif
-
- if (0 != memcmp (&ph, &m->hmac, sizeof (GNUNET_HashCode)))
- {
- /* checksum failed */
- GNUNET_break_op (0);
- return;
- }
- derive_iv (&iv, &n->decrypt_key, m->iv_seed, &my_identity);
- /* decrypt */
- if (GNUNET_OK !=
- do_decrypt (n, &iv, &m->sequence_number, &buf[ENCRYPTED_HEADER_SIZE],
- size - ENCRYPTED_HEADER_SIZE))
- return;
- pt = (struct EncryptedMessage *) buf;
-
- /* validate sequence number */
- snum = ntohl (pt->sequence_number);
- if (n->last_sequence_number_received == snum)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Received duplicate message, ignoring.\n");
- /* duplicate, ignore */
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# bytes dropped (duplicates)"),
- size, GNUNET_NO);
- return;
- }
- if ((n->last_sequence_number_received > snum) &&
- (n->last_sequence_number_received - snum > 32))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Received ancient out of sequence message, ignoring.\n");
- /* ancient out of sequence, ignore */
- GNUNET_STATISTICS_update (stats,
- gettext_noop
- ("# bytes dropped (out of sequence)"), size,
- GNUNET_NO);
- return;
- }
- if (n->last_sequence_number_received > snum)
- {
- unsigned int rotbit = 1 << (n->last_sequence_number_received - snum - 1);
-
- if ((n->last_packets_bitmap & rotbit) != 0)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Received duplicate message, ignoring.\n");
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# bytes dropped (duplicates)"),
- size, GNUNET_NO);
- /* duplicate, ignore */
- return;
- }
- n->last_packets_bitmap |= rotbit;
- }
- if (n->last_sequence_number_received < snum)
- {
- int shift = (snum - n->last_sequence_number_received);
-
- if (shift >= 8 * sizeof (n->last_packets_bitmap))
- n->last_packets_bitmap = 0;
- else
- n->last_packets_bitmap <<= shift;
- n->last_sequence_number_received = snum;
- }
-
- /* check timestamp */
- t = GNUNET_TIME_absolute_ntoh (pt->timestamp);
- if (GNUNET_TIME_absolute_get_duration (t).rel_value >
- MAX_MESSAGE_AGE.rel_value)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _("Message received far too old (%llu ms). Content
ignored.\n"),
- GNUNET_TIME_absolute_get_duration (t).rel_value);
- GNUNET_STATISTICS_update (stats,
- gettext_noop
- ("# bytes dropped (ancient message)"), size,
- GNUNET_NO);
- return;
- }
-
- /* process decrypted message(s) */
- if (n->bw_out_external_limit.value__ != pt->inbound_bw_limit.value__)
- {
-#if DEBUG_CORE_SET_QUOTA
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received %u b/s as new inbound limit for peer `%4s'\n",
- (unsigned int) ntohl (pt->inbound_bw_limit.value__),
- GNUNET_i2s (&n->peer));
-#endif
- n->bw_out_external_limit = pt->inbound_bw_limit;
- n->bw_out =
- GNUNET_BANDWIDTH_value_min (n->bw_out_external_limit,
- n->bw_out_internal_limit);
- GNUNET_BANDWIDTH_tracker_update_quota (&n->available_send_window,
- n->bw_out);
- GNUNET_TRANSPORT_set_quota (transport, &n->peer, n->bw_in, n->bw_out);
- }
- n->last_activity = GNUNET_TIME_absolute_get ();
- if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK)
- GNUNET_SCHEDULER_cancel (n->keep_alive_task);
- n->keep_alive_task =
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide
- (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
- 2), &send_keep_alive, n);
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# bytes of payload decrypted"),
- size - sizeof (struct EncryptedMessage),
GNUNET_NO);
- handle_peer_status_change (n);
- update_neighbour_performance (n, ats, ats_count);
- if (GNUNET_OK !=
- GNUNET_SERVER_mst_receive (mst, n, &buf[sizeof (struct
EncryptedMessage)],
- size - sizeof (struct EncryptedMessage),
- GNUNET_YES, GNUNET_NO))
- GNUNET_break_op (0);
-}
-
-
-/**
- * Wrapper around 'free_neighbour'; helper for 'cleaning_task'.
- */
-static int
-free_neighbour_helper (void *cls, const GNUNET_HashCode * key, void *value)
-{
- struct Neighbour *n = value;
-
- free_neighbour (n);
- return GNUNET_OK;
-}
-
-
-int
-GSC_CRYPTO_init ()
-{
- char *keyfile;
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (GSC_cfg, "GNUNETD", "HOSTKEY",
- &keyfile))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _
- ("Core service is lacking HOSTKEY configuration setting.
Exiting.\n"));
- return GNUNET_SYSERR;
- }
- my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
- GNUNET_free (keyfile);
- if (my_private_key == NULL)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Core service could not access hostkey. Exiting.\n"));
- return GNUNET_SYSERR;
- }
- GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
- GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key),
- &my_identity.hashPubKey);
-
- return GNUNET_OK;
-}
-
-
-void
-GSC_CRYPTO_done ()
-{
- if (my_private_key != NULL)
- GNUNET_CRYPTO_rsa_key_free (my_private_key);
-}
Modified: gnunet/src/core/gnunet-service-core_kx.c
===================================================================
--- gnunet/src/core/gnunet-service-core_kx.c 2011-10-06 09:02:48 UTC (rev
17241)
+++ gnunet/src/core/gnunet-service-core_kx.c 2011-10-06 11:01:23 UTC (rev
17242)
@@ -1,5 +1,34 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
/**
+ * @file core/gnunet-service-core_kx.c
+ * @brief code for managing the key exchange (SET_KEY, PING, PONG) with other
peers
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet-service-core_kx.h"
+#include "gnunet-service-core_neighbours.h"
+
+
+/**
* We're sending an (encrypted) PING to the other peer to check if he
* can decrypt. The other peer should respond with a PONG with the
* same content, except this time encrypted with the receiver's key.
@@ -29,7 +58,6 @@
};
-
/**
* Response to a PING. Includes data from the original PING
* plus initial bandwidth quota information.
@@ -112,13 +140,428 @@
/**
+ * Encapsulation for encrypted messages exchanged between
+ * peers. Followed by the actual encrypted data.
+ */
+struct EncryptedMessage
+{
+ /**
+ * Message type is either CORE_ENCRYPTED_MESSAGE.
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Random value used for IV generation.
+ */
+ uint32_t iv_seed GNUNET_PACKED;
+
+ /**
+ * MAC of the encrypted message (starting at 'sequence_number'),
+ * used to verify message integrity. Everything after this value
+ * (excluding this value itself) will be encrypted and authenticated.
+ * ENCRYPTED_HEADER_SIZE must be set to the offset of the *next* field.
+ */
+ GNUNET_HashCode hmac;
+
+ /**
+ * Sequence number, in network byte order. This field
+ * must be the first encrypted/decrypted field
+ */
+ uint32_t sequence_number GNUNET_PACKED;
+
+ /**
+ * Desired bandwidth (how much we should send to this peer / how
+ * much is the sender willing to receive)?
+ */
+ struct GNUNET_BANDWIDTH_Value32NBO inbound_bw_limit;
+
+ /**
+ * Timestamp. Used to prevent reply of ancient messages
+ * (recent messages are caught with the sequence number).
+ */
+ struct GNUNET_TIME_AbsoluteNBO timestamp;
+
+};
+
+
+/**
* Handle to peerinfo service.
*/
static struct GNUNET_PEERINFO_Handle *peerinfo;
+/**
+ * Our private key.
+ */
+static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
+/**
+ * Our public key.
+ */
+static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
+
+
+
/**
+ * Derive an authentication key from "set key" information
+ */
+static void
+derive_auth_key (struct GNUNET_CRYPTO_AuthKey *akey,
+ const struct GNUNET_CRYPTO_AesSessionKey *skey, uint32_t seed,
+ struct GNUNET_TIME_Absolute creation_time)
+{
+ static const char ctx[] = "authentication key";
+ struct GNUNET_TIME_AbsoluteNBO ctbe;
+
+
+ ctbe = GNUNET_TIME_absolute_hton (creation_time);
+ GNUNET_CRYPTO_hmac_derive_key (akey, skey, &seed, sizeof (seed), &skey->key,
+ sizeof (skey->key), &ctbe, sizeof (ctbe), ctx,
+ sizeof (ctx), NULL);
+}
+
+
+/**
+ * Derive an IV from packet information
+ */
+static void
+derive_iv (struct GNUNET_CRYPTO_AesInitializationVector *iv,
+ const struct GNUNET_CRYPTO_AesSessionKey *skey, uint32_t seed,
+ const struct GNUNET_PeerIdentity *identity)
+{
+ static const char ctx[] = "initialization vector";
+
+ GNUNET_CRYPTO_aes_derive_iv (iv, skey, &seed, sizeof (seed),
+ &identity->hashPubKey.bits,
+ sizeof (identity->hashPubKey.bits), ctx,
+ sizeof (ctx), NULL);
+}
+
+/**
+ * Derive an IV from pong packet information
+ */
+static void
+derive_pong_iv (struct GNUNET_CRYPTO_AesInitializationVector *iv,
+ const struct GNUNET_CRYPTO_AesSessionKey *skey, uint32_t seed,
+ uint32_t challenge, const struct GNUNET_PeerIdentity *identity)
+{
+ static const char ctx[] = "pong initialization vector";
+
+ GNUNET_CRYPTO_aes_derive_iv (iv, skey, &seed, sizeof (seed),
+ &identity->hashPubKey.bits,
+ sizeof (identity->hashPubKey.bits), &challenge,
+ sizeof (challenge), ctx, sizeof (ctx), NULL);
+}
+
+
+/**
+ * Encrypt size bytes from in and write the result to out. Use the
+ * key for outbound traffic of the given neighbour.
+ *
+ * @param n neighbour we are sending to
+ * @param iv initialization vector to use
+ * @param in ciphertext
+ * @param out plaintext
+ * @param size size of in/out
+ * @return GNUNET_OK on success
+ */
+static int
+do_encrypt (struct Neighbour *n,
+ const struct GNUNET_CRYPTO_AesInitializationVector *iv,
+ const void *in, void *out, size_t size)
+{
+ if (size != (uint16_t) size)
+ {
+ GNUNET_break (0);
+ return GNUNET_NO;
+ }
+ GNUNET_assert (size ==
+ GNUNET_CRYPTO_aes_encrypt (in, (uint16_t) size,
+ &n->encrypt_key, iv, out));
+ GNUNET_STATISTICS_update (stats, gettext_noop ("# bytes encrypted"), size,
+ GNUNET_NO);
+#if DEBUG_CORE > 2
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Encrypted %u bytes for `%4s' using key %u, IV %u\n",
+ (unsigned int) size, GNUNET_i2s (&n->peer),
+ (unsigned int) n->encrypt_key.crc32, GNUNET_CRYPTO_crc32_n (iv,
+
sizeof
+
(iv)));
+#endif
+ return GNUNET_OK;
+}
+
+
+
+
+/**
+ * Decrypt size bytes from in and write the result to out. Use the
+ * key for inbound traffic of the given neighbour. This function does
+ * NOT do any integrity-checks on the result.
+ *
+ * @param n neighbour we are receiving from
+ * @param iv initialization vector to use
+ * @param in ciphertext
+ * @param out plaintext
+ * @param size size of in/out
+ * @return GNUNET_OK on success
+ */
+static int
+do_decrypt (struct Neighbour *n,
+ const struct GNUNET_CRYPTO_AesInitializationVector *iv,
+ const void *in, void *out, size_t size)
+{
+ if (size != (uint16_t) size)
+ {
+ GNUNET_break (0);
+ return GNUNET_NO;
+ }
+ if ((n->status != PEER_STATE_KEY_RECEIVED) &&
+ (n->status != PEER_STATE_KEY_CONFIRMED))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (size !=
+ GNUNET_CRYPTO_aes_decrypt (in, (uint16_t) size, &n->decrypt_key, iv,
out))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_STATISTICS_update (stats, gettext_noop ("# bytes decrypted"), size,
+ GNUNET_NO);
+#if DEBUG_CORE > 1
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Decrypted %u bytes from `%4s' using key %u, IV %u\n",
+ (unsigned int) size, GNUNET_i2s (&n->peer),
+ (unsigned int) n->decrypt_key.crc32, GNUNET_CRYPTO_crc32_n (iv,
+
sizeof
+
(*iv)));
+#endif
+ return GNUNET_OK;
+}
+
+
+/**
+ * Start the key exchange with the given peer.
+ *
+ * @param pid identity of the peer to do a key exchange with
+ * @return key exchange information context
+ */
+struct GSC_KeyExchangeInfo *
+GSC_KX_start (const struct GNUNET_PeerIdentity *pid)
+{
+ struct GSC_KeyExchangeInfo *kx;
+
+ kx = NULL;
+ return kx;
+}
+
+
+/**
+ * Stop key exchange with the given peer. Clean up key material.
+ *
+ * @param kx key exchange to stop
+ */
+void
+GSC_KX_stop (struct GSC_KeyExchangeInfo *kx)
+{
+ if (kx->pitr != NULL)
+ {
+ GNUNET_PEERINFO_iterate_cancel (kx->pitr);
+ kx->pitr = NULL;
+ }
+ if (kx->retry_set_key_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (kx->retry_set_key_task);
+ GNUNET_free_non_null (kx->public_key);
+ GNUNET_free (kx);
+}
+
+
+/**
+ * We received a SET_KEY message. Validate and update
+ * our key material and status.
+ *
+ * @param n the neighbour from which we received message m
+ * @param m the set key message we received
+ * @param ats performance data
+ * @param ats_count number of entries in ats (excluding 0-termination)
+ */
+void
+GSC_KX_handle_set_key (struct GSC_KeyExchangeInfo *n, const struct
GNUNET_MessageHandler *msg,
+ const struct GNUNET_TRANSPORT_ATS_Information *ats,
+ uint32_t ats_count)
+{
+ const struct SetKeyMessage *m;
+ struct SetKeyMessage *m_cpy;
+ struct GNUNET_TIME_Absolute t;
+ struct GNUNET_CRYPTO_AesSessionKey k;
+ struct PingMessage *ping;
+ struct PongMessage *pong;
+ enum PeerStateMachine sender_status;
+ uint16_t size;
+
+ size = ntohs (msg->header);
+ if (size != sizeof (struct SetKeyMessage))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ m = (const struct SetKeyMessage*) msg;
+ GNUNET_STATISTICS_update (stats, gettext_noop ("# session keys received"),
+ 1, GNUNET_NO);
+
+#if DEBUG_CORE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Core service receives `%s' request from `%4s'.\n", "SET_KEY",
+ GNUNET_i2s (&n->peer));
+#endif
+ if (n->public_key == NULL)
+ {
+ if (n->pitr != NULL)
+ {
+#if DEBUG_CORE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Ignoring `%s' message due to lack of public key for peer
(still trying to obtain one).\n",
+ "SET_KEY");
+#endif
+ return;
+ }
+#if DEBUG_CORE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Lacking public key for peer, trying to obtain one
(handle_set_key).\n");
+#endif
+ m_cpy = GNUNET_malloc (sizeof (struct SetKeyMessage));
+ memcpy (m_cpy, m, sizeof (struct SetKeyMessage));
+ /* lookup n's public key, then try again */
+ GNUNET_assert (n->skm == NULL);
+ n->skm = m_cpy;
+ n->pitr =
+ GNUNET_PEERINFO_iterate (peerinfo, &n->peer, GNUNET_TIME_UNIT_MINUTES,
+ &process_hello_retry_handle_set_key, n);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop
+ ("# SET_KEY messages deferred (need public
key)"),
+ 1, GNUNET_NO);
+ return;
+ }
+ if (0 !=
+ memcmp (&m->target, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _
+ ("Received `%s' message that was for `%s', not for me.
Ignoring.\n"),
+ "SET_KEY", GNUNET_i2s (&m->target));
+ return;
+ }
+ if ((ntohl (m->purpose.size) !=
+ sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
+ sizeof (struct GNUNET_TIME_AbsoluteNBO) +
+ sizeof (struct GNUNET_CRYPTO_RsaEncryptedData) +
+ sizeof (struct GNUNET_PeerIdentity)) ||
+ (GNUNET_OK !=
+ GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_SET_KEY, &m->purpose,
+ &m->signature, n->public_key)))
+ {
+ /* invalid signature */
+ GNUNET_break_op (0);
+ return;
+ }
+ t = GNUNET_TIME_absolute_ntoh (m->creation_time);
+ if (((n->status == PEER_STATE_KEY_RECEIVED) ||
+ (n->status == PEER_STATE_KEY_CONFIRMED)) &&
+ (t.abs_value < n->decrypt_key_created.abs_value))
+ {
+ /* this could rarely happen due to massive re-ordering of
+ * messages on the network level, but is most likely either
+ * a bug or some adversary messing with us. Report. */
+ GNUNET_break_op (0);
+ return;
+ }
+#if DEBUG_CORE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Decrypting key material.\n");
+#endif
+ if ((GNUNET_CRYPTO_rsa_decrypt
+ (my_private_key, &m->encrypted_key, &k,
+ sizeof (struct GNUNET_CRYPTO_AesSessionKey)) !=
+ sizeof (struct GNUNET_CRYPTO_AesSessionKey)) ||
+ (GNUNET_OK != GNUNET_CRYPTO_aes_check_session_key (&k)))
+ {
+ /* failed to decrypt !? */
+ GNUNET_break_op (0);
+ return;
+ }
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# SET_KEY messages decrypted"), 1,
+ GNUNET_NO);
+ n->decrypt_key = k;
+ if (n->decrypt_key_created.abs_value != t.abs_value)
+ {
+ /* fresh key, reset sequence numbers */
+ n->last_sequence_number_received = 0;
+ n->last_packets_bitmap = 0;
+ n->decrypt_key_created = t;
+ }
+ update_neighbour_performance (n, ats, ats_count);
+ sender_status = (enum PeerStateMachine) ntohl (m->sender_status);
+ switch (n->status)
+ {
+ case PEER_STATE_DOWN:
+ n->status = PEER_STATE_KEY_RECEIVED;
+#if DEBUG_CORE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Responding to `%s' with my own key.\n", "SET_KEY");
+#endif
+ send_key (n);
+ break;
+ case PEER_STATE_KEY_SENT:
+ case PEER_STATE_KEY_RECEIVED:
+ n->status = PEER_STATE_KEY_RECEIVED;
+ if ((sender_status != PEER_STATE_KEY_RECEIVED) &&
+ (sender_status != PEER_STATE_KEY_CONFIRMED))
+ {
+#if DEBUG_CORE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Responding to `%s' with my own key (other peer has status
%u).\n",
+ "SET_KEY", (unsigned int) sender_status);
+#endif
+ send_key (n);
+ }
+ break;
+ case PEER_STATE_KEY_CONFIRMED:
+ if ((sender_status != PEER_STATE_KEY_RECEIVED) &&
+ (sender_status != PEER_STATE_KEY_CONFIRMED))
+ {
+#if DEBUG_CORE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Responding to `%s' with my own key (other peer has status
%u), I was already fully up.\n",
+ "SET_KEY", (unsigned int) sender_status);
+#endif
+ send_key (n);
+ }
+ break;
+ default:
+ GNUNET_break (0);
+ break;
+ }
+ if (n->pending_ping != NULL)
+ {
+ ping = n->pending_ping;
+ n->pending_ping = NULL;
+ handle_ping (n, ping, NULL, 0);
+ GNUNET_free (ping);
+ }
+ if (n->pending_pong != NULL)
+ {
+ pong = n->pending_pong;
+ n->pending_pong = NULL;
+ handle_pong (n, pong, NULL, 0);
+ GNUNET_free (pong);
+ }
+}
+
+
+/**
* We received a PING message. Validate and transmit
* PONG.
*
@@ -127,17 +570,44 @@
* @param ats performance data
* @param ats_count number of entries in ats (excluding 0-termination)
*/
-static void
-handle_ping (struct Neighbour *n, const struct PingMessage *m,
- const struct GNUNET_TRANSPORT_ATS_Information *ats,
- uint32_t ats_count)
+void
+GSC_KX_handle_ping (struct GSC_KeyExchangeInfo *n, const struct
GNUNET_MessageHeader *msg,
+ const struct GNUNET_TRANSPORT_ATS_Information *ats,
+ uint32_t ats_count)
{
+ const struct PingMessage *m;
struct PingMessage t;
struct PongMessage tx;
struct PongMessage *tp;
struct MessageEntry *me;
struct GNUNET_CRYPTO_AesInitializationVector iv;
+ size_t size;
+ msize = ntohs (msg->size);
+ if (msize != sizeof (struct PingMessage))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ GNUNET_STATISTICS_update (stats, gettext_noop ("# PING messages received"),
+ 1, GNUNET_NO);
+
+#if FIXME
+ if ((n->status != PEER_STATE_KEY_RECEIVED) &&
+ (n->status != PEER_STATE_KEY_CONFIRMED))
+ {
+#if DEBUG_CORE > 1
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Core service receives `%s' request from `%4s' but have not
processed key; marking as pending.\n",
+ "PING", GNUNET_i2s (&n->peer));
+#endif
+ GNUNET_free_non_null (n->pending_ping);
+ n->pending_ping = GNUNET_malloc (sizeof (struct PingMessage));
+ memcpy (n->pending_ping, message, sizeof (struct PingMessage));
+ return;
+ }
+#endif
+ m = (const struct PingMessage*) msg;
#if DEBUG_CORE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Core service receives `%s' request from `%4s'.\n", "PING",
@@ -219,18 +689,46 @@
* @param ats performance data
* @param ats_count number of entries in ats (excluding 0-termination)
*/
-static void
-handle_pong (struct Neighbour *n, const struct PongMessage *m,
- const struct GNUNET_TRANSPORT_ATS_Information *ats,
- uint32_t ats_count)
+void
+GSC_KX_handle_pong (struct GSC_KeyExchangeInfo *n, const struct
GNUNET_MessageHeader *msg,
+ const struct GNUNET_TRANSPORT_ATS_Information *ats,
+ uint32_t ats_count)
{
+ const struct PongMessage *m;
struct PongMessage t;
struct ConnectNotifyMessage *cnm;
struct GNUNET_CRYPTO_AesInitializationVector iv;
char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
struct GNUNET_TRANSPORT_ATS_Information *mats;
+ uint16_t msize;
size_t size;
+ msize = ntohs (msg->size);
+ if (msize != sizeof (struct PongMessage))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ GNUNET_STATISTICS_update (stats, gettext_noop ("# PONG messages received"),
+ 1, GNUNET_NO);
+
+#if FIXME
+ if ((n->status != PEER_STATE_KEY_RECEIVED) &&
+ (n->status != PEER_STATE_KEY_CONFIRMED))
+ {
+#if DEBUG_CORE > 1
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Core service receives `%s' request from `%4s' but have not
processed key; marking as pending.\n",
+ "PONG", GNUNET_i2s (&n->peer));
+#endif
+ GNUNET_free_non_null (n->pending_pong);
+ n->pending_pong = GNUNET_malloc (sizeof (struct PongMessage));
+ memcpy (n->pending_pong, message, sizeof (struct PongMessage));
+ return;
+ }
+#endif
+
+ m = (const struct PongMessage*) msg;
#if DEBUG_HANDSHAKE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Core service receives `%s' response from `%4s'.\n", "PONG",
@@ -357,177 +855,29 @@
GNUNET_break (0);
break;
}
-}
-
-/**
- * We received a SET_KEY message. Validate and update
- * our key material and status.
- *
- * @param n the neighbour from which we received message m
- * @param m the set key message we received
- * @param ats performance data
- * @param ats_count number of entries in ats (excluding 0-termination)
- */
-static void
-handle_set_key (struct Neighbour *n, const struct SetKeyMessage *m,
- const struct GNUNET_TRANSPORT_ATS_Information *ats,
- uint32_t ats_count)
-{
- struct SetKeyMessage *m_cpy;
- struct GNUNET_TIME_Absolute t;
- struct GNUNET_CRYPTO_AesSessionKey k;
- struct PingMessage *ping;
- struct PongMessage *pong;
- enum PeerStateMachine sender_status;
-
-#if DEBUG_CORE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Core service receives `%s' request from `%4s'.\n", "SET_KEY",
- GNUNET_i2s (&n->peer));
-#endif
- if (n->public_key == NULL)
+#if FIXME
+ if (n->status == PEER_STATE_KEY_CONFIRMED)
{
- if (n->pitr != NULL)
+ now = GNUNET_TIME_absolute_get ();
+ n->last_activity = now;
+ changed = GNUNET_YES;
+ if (!up)
{
-#if DEBUG_CORE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Ignoring `%s' message due to lack of public key for peer
(still trying to obtain one).\n",
- "SET_KEY");
-#endif
- return;
+ GNUNET_STATISTICS_update (stats, gettext_noop ("# established sessions"),
+ 1, GNUNET_NO);
+ n->time_established = now;
}
-#if DEBUG_CORE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Lacking public key for peer, trying to obtain one
(handle_set_key).\n");
-#endif
- m_cpy = GNUNET_malloc (sizeof (struct SetKeyMessage));
- memcpy (m_cpy, m, sizeof (struct SetKeyMessage));
- /* lookup n's public key, then try again */
- GNUNET_assert (n->skm == NULL);
- n->skm = m_cpy;
- n->pitr =
- GNUNET_PEERINFO_iterate (peerinfo, &n->peer, GNUNET_TIME_UNIT_MINUTES,
- &process_hello_retry_handle_set_key, n);
- GNUNET_STATISTICS_update (stats,
- gettext_noop
- ("# SET_KEY messages deferred (need public
key)"),
- 1, GNUNET_NO);
- return;
+ if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (n->keep_alive_task);
+ n->keep_alive_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide
+
(GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
+ 2), &send_keep_alive, n);
}
- if (0 !=
- memcmp (&m->target, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- _
- ("Received `%s' message that was for `%s', not for me.
Ignoring.\n"),
- "SET_KEY", GNUNET_i2s (&m->target));
- return;
- }
- if ((ntohl (m->purpose.size) !=
- sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
- sizeof (struct GNUNET_TIME_AbsoluteNBO) +
- sizeof (struct GNUNET_CRYPTO_RsaEncryptedData) +
- sizeof (struct GNUNET_PeerIdentity)) ||
- (GNUNET_OK !=
- GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_SET_KEY, &m->purpose,
- &m->signature, n->public_key)))
- {
- /* invalid signature */
- GNUNET_break_op (0);
- return;
- }
- t = GNUNET_TIME_absolute_ntoh (m->creation_time);
- if (((n->status == PEER_STATE_KEY_RECEIVED) ||
- (n->status == PEER_STATE_KEY_CONFIRMED)) &&
- (t.abs_value < n->decrypt_key_created.abs_value))
- {
- /* this could rarely happen due to massive re-ordering of
- * messages on the network level, but is most likely either
- * a bug or some adversary messing with us. Report. */
- GNUNET_break_op (0);
- return;
- }
-#if DEBUG_CORE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Decrypting key material.\n");
+ if (changed)
+ handle_peer_status_change (n);
#endif
- if ((GNUNET_CRYPTO_rsa_decrypt
- (my_private_key, &m->encrypted_key, &k,
- sizeof (struct GNUNET_CRYPTO_AesSessionKey)) !=
- sizeof (struct GNUNET_CRYPTO_AesSessionKey)) ||
- (GNUNET_OK != GNUNET_CRYPTO_aes_check_session_key (&k)))
- {
- /* failed to decrypt !? */
- GNUNET_break_op (0);
- return;
- }
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# SET_KEY messages decrypted"), 1,
- GNUNET_NO);
- n->decrypt_key = k;
- if (n->decrypt_key_created.abs_value != t.abs_value)
- {
- /* fresh key, reset sequence numbers */
- n->last_sequence_number_received = 0;
- n->last_packets_bitmap = 0;
- n->decrypt_key_created = t;
- }
- update_neighbour_performance (n, ats, ats_count);
- sender_status = (enum PeerStateMachine) ntohl (m->sender_status);
- switch (n->status)
- {
- case PEER_STATE_DOWN:
- n->status = PEER_STATE_KEY_RECEIVED;
-#if DEBUG_CORE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Responding to `%s' with my own key.\n", "SET_KEY");
-#endif
- send_key (n);
- break;
- case PEER_STATE_KEY_SENT:
- case PEER_STATE_KEY_RECEIVED:
- n->status = PEER_STATE_KEY_RECEIVED;
- if ((sender_status != PEER_STATE_KEY_RECEIVED) &&
- (sender_status != PEER_STATE_KEY_CONFIRMED))
- {
-#if DEBUG_CORE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Responding to `%s' with my own key (other peer has status
%u).\n",
- "SET_KEY", (unsigned int) sender_status);
-#endif
- send_key (n);
- }
- break;
- case PEER_STATE_KEY_CONFIRMED:
- if ((sender_status != PEER_STATE_KEY_RECEIVED) &&
- (sender_status != PEER_STATE_KEY_CONFIRMED))
- {
-#if DEBUG_CORE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Responding to `%s' with my own key (other peer has status
%u), I was already fully up.\n",
- "SET_KEY", (unsigned int) sender_status);
-#endif
- send_key (n);
- }
- break;
- default:
- GNUNET_break (0);
- break;
- }
- if (n->pending_ping != NULL)
- {
- ping = n->pending_ping;
- n->pending_ping = NULL;
- handle_ping (n, ping, NULL, 0);
- GNUNET_free (ping);
- }
- if (n->pending_pong != NULL)
- {
- pong = n->pending_pong;
- n->pending_pong = NULL;
- handle_pong (n, pong, NULL, 0);
- GNUNET_free (pong);
- }
}
@@ -907,52 +1257,322 @@
}
-struct GSC_KeyExchangeInfo *
-GSC_KX_start (const struct GNUNET_PeerIdentity *pid)
+/**
+ * Encrypt and transmit a message with the given payload.
+ *
+ * @param kx key exchange context
+ * @param payload payload of the message
+ * @param payload_size number of bytes in 'payload'
+ */
+void
+GSC_KX_encrypt_and_transmit (struct GSC_KeyExchangeInfo *kx,
+ const void *payload,
+ size_t payload_size)
{
- struct GSC_KeyExchangeInfo *kx;
+ char pbuf[GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE + sizeof (struct
EncryptedMessage)]; /* plaintext */
+ size_t used;
+ struct EncryptedMessage *em; /* encrypted message */
+ struct EncryptedMessage *ph; /* plaintext header */
+ struct MessageEntry *me;
+ unsigned int priority;
+ struct GNUNET_TIME_Absolute deadline;
+ struct GNUNET_TIME_Relative retry_time;
+ struct GNUNET_CRYPTO_AesInitializationVector iv;
+ struct GNUNET_CRYPTO_AuthKey auth_key;
- kx = NULL;
- return kx;
-}
+#if DEBUG_CORE_QUOTA
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending %u b/s as new limit to peer `%4s'\n",
+ (unsigned int) ntohl (n->bw_in.value__), GNUNET_i2s (&n->peer));
+#endif
+ ph->iv_seed =
+ htonl (GNUNET_CRYPTO_random_u32
+ (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX));
+ ph->sequence_number = htonl (++n->last_sequence_number_sent);
+ ph->inbound_bw_limit = n->bw_in;
+ ph->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
+ /* setup encryption message header */
+ me = GNUNET_malloc (sizeof (struct MessageEntry) + used);
+ me->deadline = deadline;
+ me->priority = priority;
+ me->size = used;
+ em = (struct EncryptedMessage *) &me[1];
+ em->header.size = htons (used);
+ em->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE);
+ em->iv_seed = ph->iv_seed;
+ derive_iv (&iv, &n->encrypt_key, ph->iv_seed, &n->peer);
+ /* encrypt */
+#if DEBUG_HANDSHAKE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Encrypting %u bytes of plaintext messages for `%4s' for
transmission in %llums.\n",
+ (unsigned int) used - ENCRYPTED_HEADER_SIZE,
+ GNUNET_i2s (&n->peer),
+ (unsigned long long)
+ GNUNET_TIME_absolute_get_remaining (deadline).rel_value);
+#endif
+ GNUNET_assert (GNUNET_OK ==
+ do_encrypt (n, &iv, &ph->sequence_number,
&em->sequence_number,
+ used - ENCRYPTED_HEADER_SIZE));
+ derive_auth_key (&auth_key, &n->encrypt_key, ph->iv_seed,
+ n->encrypt_key_created);
+ GNUNET_CRYPTO_hmac (&auth_key, &em->sequence_number,
+ used - ENCRYPTED_HEADER_SIZE, &em->hmac);
+#if DEBUG_HANDSHAKE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Authenticated %u bytes of ciphertext %u: `%s'\n",
+ used - ENCRYPTED_HEADER_SIZE,
+ GNUNET_CRYPTO_crc32_n (&em->sequence_number,
+ used - ENCRYPTED_HEADER_SIZE),
+ GNUNET_h2s (&em->hmac));
+#endif
+ GDS_NEIGHBOURS_transmit (&kx->peer,
+ &em->header,
+ GNUNET_TIME_UNIT_FOREVER_REL);
+}
+
+/**
+ * We received an encrypted message. Decrypt, validate and
+ * pass on to the appropriate clients.
+ *
+ * @param n target of the message
+ * @param m encrypted message
+ * @param ats performance data
+ * @param ats_count number of entries in ats (excluding 0-termination)
+ */
void
-GSC_KX_stop (struct GSC_KeyExchangeInfo *kx)
+GSC_KX_handle_encrypted_message (struct GSC_KeyExchangeInfo *n,
+ const struct GNUNET_MessageHeader *msg,
+ const struct GNUNET_TRANSPORT_ATS_Information
*ats,
+ uint32_t ats_count)
{
- if (kx->pitr != NULL)
+ const struct EncryptedMessage *m;
+ char buf[size];
+ struct EncryptedMessage *pt; /* plaintext */
+ GNUNET_HashCode ph;
+ uint32_t snum;
+ struct GNUNET_TIME_Absolute t;
+ struct GNUNET_CRYPTO_AesInitializationVector iv;
+ struct GNUNET_CRYPTO_AuthKey auth_key;
+ uint16_t size = ntohs (msg->size);
+
+ if (size <
+ sizeof (struct EncryptedMessage) + sizeof (struct GNUNET_MessageHeader))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ m = (const struct EncryptedMessage*) msg;
+#if FIXME
+ if ((n->status != PEER_STATE_KEY_RECEIVED) &&
+ (n->status != PEER_STATE_KEY_CONFIRMED))
+ {
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop
+ ("# failed to decrypt message (no session
key)"),
+ 1, GNUNET_NO);
+ send_key (n);
+ return;
+ }
+#endif
+
+#if DEBUG_CORE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Core service receives `%s' request from `%4s'.\n",
+ "ENCRYPTED_MESSAGE", GNUNET_i2s (&n->peer));
+#endif
+ /* validate hash */
+ derive_auth_key (&auth_key, &n->decrypt_key, m->iv_seed,
+ n->decrypt_key_created);
+ GNUNET_CRYPTO_hmac (&auth_key, &m->sequence_number,
+ size - ENCRYPTED_HEADER_SIZE, &ph);
+#if DEBUG_HANDSHAKE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Re-Authenticated %u bytes of ciphertext (`%u'): `%s'\n",
+ (unsigned int) size - ENCRYPTED_HEADER_SIZE,
+ GNUNET_CRYPTO_crc32_n (&m->sequence_number,
+ size - ENCRYPTED_HEADER_SIZE),
+ GNUNET_h2s (&ph));
+#endif
+
+ if (0 != memcmp (&ph, &m->hmac, sizeof (GNUNET_HashCode)))
{
- GNUNET_PEERINFO_iterate_cancel (kx->pitr);
- kx->pitr = NULL;
+ /* checksum failed */
+ GNUNET_break_op (0);
+ return;
}
- if (kx->retry_set_key_task != GNUNET_SCHEDULER_NO_TASK)
- GNUNET_SCHEDULER_cancel (kx->retry_set_key_task);
- GNUNET_free_non_null (kx->public_key);
- GNUNET_free (kx);
+ derive_iv (&iv, &n->decrypt_key, m->iv_seed, &my_identity);
+ /* decrypt */
+ if (GNUNET_OK !=
+ do_decrypt (n, &iv, &m->sequence_number, &buf[ENCRYPTED_HEADER_SIZE],
+ size - ENCRYPTED_HEADER_SIZE))
+ return;
+ pt = (struct EncryptedMessage *) buf;
+
+ /* validate sequence number */
+ snum = ntohl (pt->sequence_number);
+ if (n->last_sequence_number_received == snum)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Received duplicate message, ignoring.\n");
+ /* duplicate, ignore */
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# bytes dropped (duplicates)"),
+ size, GNUNET_NO);
+ return;
+ }
+ if ((n->last_sequence_number_received > snum) &&
+ (n->last_sequence_number_received - snum > 32))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Received ancient out of sequence message, ignoring.\n");
+ /* ancient out of sequence, ignore */
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop
+ ("# bytes dropped (out of sequence)"), size,
+ GNUNET_NO);
+ return;
+ }
+ if (n->last_sequence_number_received > snum)
+ {
+ unsigned int rotbit = 1 << (n->last_sequence_number_received - snum - 1);
+
+ if ((n->last_packets_bitmap & rotbit) != 0)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Received duplicate message, ignoring.\n");
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# bytes dropped (duplicates)"),
+ size, GNUNET_NO);
+ /* duplicate, ignore */
+ return;
+ }
+ n->last_packets_bitmap |= rotbit;
+ }
+ if (n->last_sequence_number_received < snum)
+ {
+ int shift = (snum - n->last_sequence_number_received);
+
+ if (shift >= 8 * sizeof (n->last_packets_bitmap))
+ n->last_packets_bitmap = 0;
+ else
+ n->last_packets_bitmap <<= shift;
+ n->last_sequence_number_received = snum;
+ }
+
+ /* check timestamp */
+ t = GNUNET_TIME_absolute_ntoh (pt->timestamp);
+ if (GNUNET_TIME_absolute_get_duration (t).rel_value >
+ MAX_MESSAGE_AGE.rel_value)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Message received far too old (%llu ms). Content
ignored.\n"),
+ GNUNET_TIME_absolute_get_duration (t).rel_value);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop
+ ("# bytes dropped (ancient message)"), size,
+ GNUNET_NO);
+ return;
+ }
+
+ /* process decrypted message(s) */
+ if (n->bw_out_external_limit.value__ != pt->inbound_bw_limit.value__)
+ {
+#if DEBUG_CORE_SET_QUOTA
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received %u b/s as new inbound limit for peer `%4s'\n",
+ (unsigned int) ntohl (pt->inbound_bw_limit.value__),
+ GNUNET_i2s (&n->peer));
+#endif
+ n->bw_out_external_limit = pt->inbound_bw_limit;
+ n->bw_out =
+ GNUNET_BANDWIDTH_value_min (n->bw_out_external_limit,
+ n->bw_out_internal_limit);
+ GNUNET_BANDWIDTH_tracker_update_quota (&n->available_send_window,
+ n->bw_out);
+ GNUNET_TRANSPORT_set_quota (transport, &n->peer, n->bw_in, n->bw_out);
+ }
+ n->last_activity = GNUNET_TIME_absolute_get ();
+ if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (n->keep_alive_task);
+ n->keep_alive_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide
+ (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
+ 2), &send_keep_alive, n);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# bytes of payload decrypted"),
+ size - sizeof (struct EncryptedMessage),
GNUNET_NO);
+ handle_peer_status_change (n);
+ update_neighbour_performance (n, ats, ats_count);
+ if (GNUNET_OK !=
+ GNUNET_SERVER_mst_receive (mst, n, &buf[sizeof (struct
EncryptedMessage)],
+ size - sizeof (struct EncryptedMessage),
+ GNUNET_YES, GNUNET_NO))
+ GNUNET_break_op (0);
}
+
+
+/**
+ * Initialize KX subsystem.
+ *
+ * @return GNUNET_OK on success, GNUNET_SYSERR on failure
+ */
int
GSC_KX_init ()
{
+ char *keyfile;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (GSC_cfg, "GNUNETD", "HOSTKEY",
+ &keyfile))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Core service is lacking HOSTKEY configuration setting.
Exiting.\n"));
+ return GNUNET_SYSERR;
+ }
+ my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
+ GNUNET_free (keyfile);
+ if (my_private_key == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Core service could not access hostkey. Exiting.\n"));
+ return GNUNET_SYSERR;
+ }
+ GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
+ GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key),
+ &my_identity.hashPubKey);
peerinfo = GNUNET_PEERINFO_connect (cfg);
if (NULL == peerinfo)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
_("Could not access PEERINFO service. Exiting.\n"));
+ GNUNET_CRYPTO_rsa_key_free (my_private_key);
+ my_private_key = NULL;
return GNUNET_SYSERR;
}
return GNUNET_OK;
}
+/**
+ * Shutdown KX subsystem.
+ */
void
GSC_KX_done ()
{
+ if (my_private_key != NULL)
+ {
+ GNUNET_CRYPTO_rsa_key_free (my_private_key);
+ my_private_key = NULL;
+ }
if (peerinfo != NULL)
{
GNUNET_PEERINFO_disconnect (peerinfo);
peerinfo = NULL;
}
+}
-}
+/* end of gnunet-service-core_kx.c */
Modified: gnunet/src/core/gnunet-service-core_kx.h
===================================================================
--- gnunet/src/core/gnunet-service-core_kx.h 2011-10-06 09:02:48 UTC (rev
17241)
+++ gnunet/src/core/gnunet-service-core_kx.h 2011-10-06 11:01:23 UTC (rev
17242)
@@ -1,3 +1,37 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file core/gnunet-service-core_kx.h
+ * @brief code for managing the key exchange (SET_KEY, PING, PONG) with other
peers
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_CORE_KX_H
+#define GNUNET_SERVICE_CORE_KX_H
+
+#include "gnunet_util_lib.h"
+
+
+/**
+ * Information about the status of a key exchange with another peer.
+ */
struct GSC_KeyExchangeInfo
{
@@ -75,3 +109,117 @@
enum PeerStateMachine status;
};
+
+
+/**
+ * We received a SET_KEY message. Validate and update
+ * our key material and status.
+ *
+ * @param kx key exchange status for the corresponding peer
+ * @param msg the set key message we received
+ * @param ats performance data
+ * @param ats_count number of entries in ats (excluding 0-termination)
+ */
+void
+GSC_KX_handle_set_key (struct GSC_KeyExchangeInfo *n,
+ const struct GNUNET_MessageHandler *msg,
+ const struct GNUNET_TRANSPORT_ATS_Information *ats,
+ uint32_t ats_count);
+
+
+/**
+ * We received a PING message. Validate and transmit
+ * a PONG message.
+ *
+ * @param kx key exchange status for the corresponding peer
+ * @param msg the encrypted PING message itself
+ * @param ats performance data
+ * @param ats_count number of entries in ats (excluding 0-termination)
+ */
+void
+GSC_KX_handle_ping (struct GSC_KeyExchangeInfo *kx,
+ const struct GNUNET_MessageHeader *msg,
+ const struct GNUNET_TRANSPORT_ATS_Information *ats,
+ uint32_t ats_count);
+
+
+/**
+ * We received a PONG message. Validate and update our status.
+ *
+ * @param kx key exchange status for the corresponding peer
+ * @param msg the encrypted PONG message itself
+ * @param ats performance data
+ * @param ats_count number of entries in ats (excluding 0-termination)
+ */
+void
+GSC_KX_handle_pong (struct GSC_KeyExchangeInfo *kx,
+ const struct GNUNET_MessageHeader *msg,
+ const struct GNUNET_TRANSPORT_ATS_Information *ats,
+ uint32_t ats_count);
+
+
+/**
+ * Encrypt and transmit a message with the given payload.
+ *
+ * @param kx key exchange context
+ * @param payload payload of the message
+ * @param payload_size number of bytes in 'payload'
+ */
+void
+GSC_KX_encrypt_and_transmit (struct GSC_KeyExchangeInfo *kx,
+ const void *payload,
+ size_t payload_size);
+
+
+/**
+ * We received an encrypted message. Decrypt, validate and
+ * pass on to the appropriate clients.
+ *
+ * @param kx key exchange information context
+ * @param msg encrypted message
+ * @param ats performance data
+ * @param ats_count number of entries in ats (excluding 0-termination)
+ */
+void
+GSC_KX_handle_encrypted_message (struct GSC_KeyExchangeInfo *kx,
+ const struct GNUNET_MessageHeader *msg,
+ const struct GNUNET_TRANSPORT_ATS_Information
*ats,
+ uint32_t ats_count);
+
+
+/**
+ * Start the key exchange with the given peer.
+ *
+ * @param pid identity of the peer to do a key exchange with
+ * @return key exchange information context
+ */
+struct GSC_KeyExchangeInfo *
+GSC_KX_start (const struct GNUNET_PeerIdentity *pid);
+
+
+/**
+ * Stop key exchange with the given peer. Clean up key material.
+ *
+ * @param kx key exchange to stop
+ */
+void
+GSC_KX_stop (struct GSC_KeyExchangeInfo *kx);
+
+
+/**
+ * Initialize KX subsystem.
+ *
+ * @return GNUNET_OK on success, GNUNET_SYSERR on failure
+ */
+int
+GSC_KX_init (void);
+
+
+/**
+ * Shutdown KX subsystem.
+ */
+void
+GSC_KX_done (void);
+
+#endif
+/* end of gnunet-service-core_kx.h */
Modified: gnunet/src/core/gnunet-service-core_neighbours.c
===================================================================
--- gnunet/src/core/gnunet-service-core_neighbours.c 2011-10-06 09:02:48 UTC
(rev 17241)
+++ gnunet/src/core/gnunet-service-core_neighbours.c 2011-10-06 11:01:23 UTC
(rev 17242)
@@ -27,8 +27,9 @@
#include "gnunet_util_lib.h"
#include "gnunet_transport_service.h"
#include "gnunet_service_core.h"
-#include "gnunet_service_core-neighbours.h"
-#include "gnunet_service_core-kx.h"
+#include "gnunet_service_core_neighbours.h"
+#include "gnunet_service_core_kx.h"
+#include "gnunet_service_core_sessions.h"
/**
@@ -112,7 +113,6 @@
*/
struct GNUNET_BANDWIDTH_Tracker available_recv_window;
-
};
@@ -127,7 +127,6 @@
static struct GNUNET_TRANSPORT_Handle *transport;
-
/**
* Find the entry for the given neighbour.
*
@@ -167,6 +166,7 @@
GNUNET_TRANSPORT_notify_transmit_ready_cancel (n->th);
n->th = NULL;
}
+ GSC_SESSION_end (&n->peer);
if (NULL != n->kx)
{
GSC_KX_stop (n->kx);
@@ -219,11 +219,7 @@
m = n->message_head;
if (m == NULL)
{
-#if DEBUG_CORE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Encrypted message queue empty, no messages added to buffer
for `%4s'\n",
- GNUNET_i2s (&n->peer));
-#endif
+ GNUNET_break (0);
return 0;
}
GNUNET_CONTAINER_DLL_remove (n->encrypted_head, n->encrypted_tail, m);
@@ -278,7 +274,12 @@
return; /* request already pending */
m = n->message_head;
if (m == NULL)
+ {
+ /* notify sessions that the queue is empty and more messages
+ could thus be queued now */
+ GSC_SESSIONS_solicit (&n->peer);
return;
+ }
#if DEBUG_CORE > 1
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Asking transport for transmission of %u bytes to `%4s' in next
%llu ms\n",
@@ -404,11 +405,7 @@
uint32_t ats_count)
{
struct Neighbour *n;
- struct GNUNET_TIME_Absolute now;
- int up;
uint16_t type;
- uint16_t size;
- int changed;
#if DEBUG_CORE > 1
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -427,116 +424,30 @@
GNUNET_break (0);
return;
}
-
-
- changed = GNUNET_NO;
- up = (n->status == PEER_STATE_KEY_CONFIRMED);
type = ntohs (message->type);
- size = ntohs (message->size);
switch (type)
{
case GNUNET_MESSAGE_TYPE_CORE_SET_KEY:
- if (size != sizeof (struct SetKeyMessage))
- {
- GNUNET_break_op (0);
- return;
- }
- GNUNET_STATISTICS_update (stats, gettext_noop ("# session keys received"),
- 1, GNUNET_NO);
- handle_set_key (n, (const struct SetKeyMessage *) message, ats, ats_count);
+ GSC_KX_handle_set_key (n->kxinfo, message, ats, ats_count);
break;
- case GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE:
- if (size <
- sizeof (struct EncryptedMessage) + sizeof (struct
GNUNET_MessageHeader))
- {
- GNUNET_break_op (0);
- return;
- }
- if ((n->status != PEER_STATE_KEY_RECEIVED) &&
- (n->status != PEER_STATE_KEY_CONFIRMED))
- {
- GNUNET_STATISTICS_update (stats,
- gettext_noop
- ("# failed to decrypt message (no session
key)"),
- 1, GNUNET_NO);
- send_key (n);
- return;
- }
- handle_encrypted_message (n, (const struct EncryptedMessage *) message,
ats,
- ats_count);
- break;
case GNUNET_MESSAGE_TYPE_CORE_PING:
- if (size != sizeof (struct PingMessage))
- {
- GNUNET_break_op (0);
- return;
- }
- GNUNET_STATISTICS_update (stats, gettext_noop ("# PING messages received"),
- 1, GNUNET_NO);
- if ((n->status != PEER_STATE_KEY_RECEIVED) &&
- (n->status != PEER_STATE_KEY_CONFIRMED))
- {
-#if DEBUG_CORE > 1
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Core service receives `%s' request from `%4s' but have not
processed key; marking as pending.\n",
- "PING", GNUNET_i2s (&n->peer));
-#endif
- GNUNET_free_non_null (n->pending_ping);
- n->pending_ping = GNUNET_malloc (sizeof (struct PingMessage));
- memcpy (n->pending_ping, message, sizeof (struct PingMessage));
- return;
- }
- handle_ping (n, (const struct PingMessage *) message, ats, ats_count);
+ GSC_KX_handle_ping (n->kxinfo, message, ats, ats_count);
break;
case GNUNET_MESSAGE_TYPE_CORE_PONG:
- if (size != sizeof (struct PongMessage))
- {
- GNUNET_break_op (0);
- return;
- }
- GNUNET_STATISTICS_update (stats, gettext_noop ("# PONG messages received"),
- 1, GNUNET_NO);
- if ((n->status != PEER_STATE_KEY_RECEIVED) &&
- (n->status != PEER_STATE_KEY_CONFIRMED))
- {
-#if DEBUG_CORE > 1
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Core service receives `%s' request from `%4s' but have not
processed key; marking as pending.\n",
- "PONG", GNUNET_i2s (&n->peer));
-#endif
- GNUNET_free_non_null (n->pending_pong);
- n->pending_pong = GNUNET_malloc (sizeof (struct PongMessage));
- memcpy (n->pending_pong, message, sizeof (struct PongMessage));
- return;
- }
- handle_pong (n, (const struct PongMessage *) message, ats, ats_count);
+ GSC_KX_handle_pong (n->kxinfo, message, ats, ats_count);
break;
+ case GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE:
+ GSC_KX_handle_encrypted_message (peer,
+ n->kxinfo,
+ message, ats,
+ ats_count);
+ break;
default:
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
_("Unsupported message of type %u received.\n"),
(unsigned int) type);
return;
}
- if (n->status == PEER_STATE_KEY_CONFIRMED)
- {
- now = GNUNET_TIME_absolute_get ();
- n->last_activity = now;
- changed = GNUNET_YES;
- if (!up)
- {
- GNUNET_STATISTICS_update (stats, gettext_noop ("# established sessions"),
- 1, GNUNET_NO);
- n->time_established = now;
- }
- if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK)
- GNUNET_SCHEDULER_cancel (n->keep_alive_task);
- n->keep_alive_task =
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide
-
(GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
- 2), &send_keep_alive, n);
- }
- if (changed)
- handle_peer_status_change (n);
}
@@ -552,7 +463,25 @@
const struct GNUNET_MessageHeader *msg,
struct GNUNET_TIME_Relative timeout)
{
-
+ struct MessageEntry *me;
+ struct Neighbour *n;
+ size_t msize;
+
+ n = find_neighbour (target);
+ if (NULL == n)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ msize = ntohs (msg->size);
+ me = GNUNET_malloc (sizeof (struct MessageEntry) + msize);
+ me->deadline = GNUNET_TIME_relative_to_absolute (timeout);
+ me->size = msize;
+ memcpy (&me[1], msg, msize);
+ GNUNET_CONTAINER_DLL_insert (n->message_head,
+ n->message_tail,
+ me);
+ process_queue (n);
}
Added: gnunet/src/core/gnunet-service-core_neighbours.h
===================================================================
--- gnunet/src/core/gnunet-service-core_neighbours.h
(rev 0)
+++ gnunet/src/core/gnunet-service-core_neighbours.h 2011-10-06 11:01:23 UTC
(rev 17242)
@@ -0,0 +1,63 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file core/gnunet-service-core_neighbours.h
+ * @brief code for managing low-level 'plaintext' connections with transport
(key exchange may or may not be done yet)
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_CORE_NEIGHBOURS_H
+#define GNUNET_SERVICE_CORE_NEIGHBOURS_H
+
+#include "gnunet_util_lib.h"
+
+/**
+ * Transmit the given message to the given target. Note that a
+ * non-control messages should only be transmitted after a
+ * 'GSC_SESSION_solicit' call was made (that call is always invoked
+ * when the message queue is empty). Outbound quotas and memory
+ * bounds will then be enfoced (as GSC_SESSION_solicit is only called
+ * if sufficient banwdith is available).
+ *
+ * @param target peer that should receive the message (must be connected)
+ * @param msg message to transmit
+ * @param timeout by when should the transmission be done?
+ */
+void
+GDS_NEIGHBOURS_transmit (const struct GNUNET_PeerIdentity *target,
+ const struct GNUNET_MessageHeader *msg,
+ struct GNUNET_TIME_Relative timeout);
+
+
+/**
+ * Initialize neighbours subsystem.
+ */
+int
+GSC_NEIGHBOURS_init (void);
+
+
+/**
+ * Shutdown neighbours subsystem.
+ */
+void
+GSC_NEIGHBOURS_done (void);
+
+
+#endif
Deleted: gnunet/src/core/gnunet-service-core_plan.c
===================================================================
--- gnunet/src/core/gnunet-service-core_plan.c 2011-10-06 09:02:48 UTC (rev
17241)
+++ gnunet/src/core/gnunet-service-core_plan.c 2011-10-06 11:01:23 UTC (rev
17242)
@@ -1,563 +0,0 @@
-
-
-
-/**
- * Select messages for transmission. This heuristic uses a combination
- * of earliest deadline first (EDF) scheduling (with bounded horizon)
- * and priority-based discard (in case no feasible schedule exist) and
- * speculative optimization (defer any kind of transmission until
- * we either create a batch of significant size, 25% of max, or until
- * we are close to a deadline). Furthermore, when scheduling the
- * heuristic also packs as many messages into the batch as possible,
- * starting with those with the earliest deadline. Yes, this is fun.
- *
- * @param n neighbour to select messages from
- * @param size number of bytes to select for transmission
- * @param retry_time set to the time when we should try again
- * (only valid if this function returns zero)
- * @return number of bytes selected, or 0 if we decided to
- * defer scheduling overall; in that case, retry_time is set.
- */
-static size_t
-select_messages (struct Neighbour *n, size_t size,
- struct GNUNET_TIME_Relative *retry_time)
-{
- struct MessageEntry *pos;
- struct MessageEntry *min;
- struct MessageEntry *last;
- unsigned int min_prio;
- struct GNUNET_TIME_Absolute t;
- struct GNUNET_TIME_Absolute now;
- struct GNUNET_TIME_Relative delta;
- uint64_t avail;
- struct GNUNET_TIME_Relative slack; /* how long could we wait before
missing deadlines? */
- size_t off;
- uint64_t tsize;
- unsigned int queue_size;
- int discard_low_prio;
-
- GNUNET_assert (NULL != n->messages);
- now = GNUNET_TIME_absolute_get ();
- /* last entry in linked list of messages processed */
- last = NULL;
- /* should we remove the entry with the lowest
- * priority from consideration for scheduling at the
- * end of the loop? */
- queue_size = 0;
- tsize = 0;
- pos = n->messages;
- while (pos != NULL)
- {
- queue_size++;
- tsize += pos->size;
- pos = pos->next;
- }
- discard_low_prio = GNUNET_YES;
- while (GNUNET_YES == discard_low_prio)
- {
- min = NULL;
- min_prio = UINT_MAX;
- discard_low_prio = GNUNET_NO;
- /* calculate number of bytes available for transmission at time "t" */
- avail = GNUNET_BANDWIDTH_tracker_get_available (&n->available_send_window);
- t = now;
- /* how many bytes have we (hypothetically) scheduled so far */
- off = 0;
- /* maximum time we can wait before transmitting anything
- * and still make all of our deadlines */
- slack = GNUNET_TIME_UNIT_FOREVER_REL;
- pos = n->messages;
- /* note that we use "*2" here because we want to look
- * a bit further into the future; much more makes no
- * sense since new message might be scheduled in the
- * meantime... */
- while ((pos != NULL) && (off < size * 2))
- {
- if (pos->do_transmit == GNUNET_YES)
- {
- /* already removed from consideration */
- pos = pos->next;
- continue;
- }
- if (discard_low_prio == GNUNET_NO)
- {
- delta = GNUNET_TIME_absolute_get_difference (t, pos->deadline);
- if (delta.rel_value > 0)
- {
- // FIXME: HUH? Check!
- t = pos->deadline;
- avail +=
- GNUNET_BANDWIDTH_value_get_available_until (n->bw_out, delta);
- }
- if (avail < pos->size)
- {
- // FIXME: HUH? Check!
- discard_low_prio = GNUNET_YES; /* we could not schedule this
one! */
- }
- else
- {
- avail -= pos->size;
- /* update slack, considering both its absolute deadline
- * and relative deadlines caused by other messages
- * with their respective load */
- slack =
- GNUNET_TIME_relative_min (slack,
- GNUNET_BANDWIDTH_value_get_delay_for
- (n->bw_out, avail));
- if (pos->deadline.abs_value <= now.abs_value)
- {
- /* now or never */
- slack = GNUNET_TIME_UNIT_ZERO;
- }
- else if (GNUNET_YES == pos->got_slack)
- {
- /* should be soon now! */
- slack =
- GNUNET_TIME_relative_min (slack,
- GNUNET_TIME_absolute_get_remaining
- (pos->slack_deadline));
- }
- else
- {
- slack =
- GNUNET_TIME_relative_min (slack,
- GNUNET_TIME_absolute_get_difference
- (now, pos->deadline));
- pos->got_slack = GNUNET_YES;
- pos->slack_deadline =
- GNUNET_TIME_absolute_min (pos->deadline,
- GNUNET_TIME_relative_to_absolute
- (GNUNET_CONSTANTS_MAX_CORK_DELAY));
- }
- }
- }
- off += pos->size;
- t = GNUNET_TIME_absolute_max (pos->deadline, t); // HUH? Check!
- if (pos->priority <= min_prio)
- {
- /* update min for discard */
- min_prio = pos->priority;
- min = pos;
- }
- pos = pos->next;
- }
- if (discard_low_prio)
- {
- GNUNET_assert (min != NULL);
- /* remove lowest-priority entry from consideration */
- min->do_transmit = GNUNET_YES; /* means: discard (for now) */
- }
- last = pos;
- }
- /* guard against sending "tiny" messages with large headers without
- * urgent deadlines */
- if ((slack.rel_value > GNUNET_CONSTANTS_MAX_CORK_DELAY.rel_value) &&
- (size > 4 * off) && (queue_size <= MAX_PEER_QUEUE_SIZE - 2))
- {
- /* less than 25% of message would be filled with deadlines still
- * being met if we delay by one second or more; so just wait for
- * more data; but do not wait longer than 1s (since we don't want
- * to delay messages for a really long time either). */
- *retry_time = GNUNET_CONSTANTS_MAX_CORK_DELAY;
- /* reset do_transmit values for next time */
- while (pos != last)
- {
- pos->do_transmit = GNUNET_NO;
- pos = pos->next;
- }
- GNUNET_STATISTICS_update (stats,
- gettext_noop
- ("# transmissions delayed due to corking"), 1,
- GNUNET_NO);
-#if DEBUG_CORE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Deferring transmission for %llums due to underfull message
buffer size (%u/%u)\n",
- (unsigned long long) retry_time->rel_value, (unsigned int) off,
- (unsigned int) size);
-#endif
- return 0;
- }
- /* select marked messages (up to size) for transmission */
- off = 0;
- pos = n->messages;
- while (pos != last)
- {
- if ((pos->size <= size) && (pos->do_transmit == GNUNET_NO))
- {
- pos->do_transmit = GNUNET_YES; /* mark for transmission */
- off += pos->size;
- size -= pos->size;
-#if DEBUG_CORE > 1
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Selecting message of size %u for transmission\n",
- (unsigned int) pos->size);
-#endif
- }
- else
- {
-#if DEBUG_CORE > 1
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Not selecting message of size %u for transmission at this
time (maximum is %u)\n",
- (unsigned int) pos->size, size);
-#endif
- pos->do_transmit = GNUNET_NO; /* mark for not transmitting! */
- }
- pos = pos->next;
- }
-#if DEBUG_CORE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Selected %llu/%llu bytes of %u/%u plaintext messages for
transmission to `%4s'.\n",
- (unsigned long long) off, (unsigned long long) tsize, queue_size,
- (unsigned int) MAX_PEER_QUEUE_SIZE, GNUNET_i2s (&n->peer));
-#endif
- return off;
-}
-
-
-/**
- * Batch multiple messages into a larger buffer.
- *
- * @param n neighbour to take messages from
- * @param buf target buffer
- * @param size size of buf
- * @param deadline set to transmission deadline for the result
- * @param retry_time set to the time when we should try again
- * (only valid if this function returns zero)
- * @param priority set to the priority of the batch
- * @return number of bytes written to buf (can be zero)
- */
-static size_t
-batch_message (struct Neighbour *n, char *buf, size_t size,
- struct GNUNET_TIME_Absolute *deadline,
- struct GNUNET_TIME_Relative *retry_time, unsigned int *priority)
-{
- char ntmb[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
- struct NotifyTrafficMessage *ntm = (struct NotifyTrafficMessage *) ntmb;
- struct MessageEntry *pos;
- struct MessageEntry *prev;
- struct MessageEntry *next;
- size_t ret;
-
- ret = 0;
- *priority = 0;
- *deadline = GNUNET_TIME_UNIT_FOREVER_ABS;
- *retry_time = GNUNET_TIME_UNIT_FOREVER_REL;
- if (0 == select_messages (n, size, retry_time))
- {
-#if DEBUG_CORE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "No messages selected, will try again in %llu ms\n",
- retry_time->rel_value);
-#endif
- return 0;
- }
- ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND);
- ntm->ats_count = htonl (0);
- ntm->ats.type = htonl (0);
- ntm->ats.value = htonl (0);
- ntm->peer = n->peer;
- pos = n->messages;
- prev = NULL;
- while ((pos != NULL) && (size >= sizeof (struct GNUNET_MessageHeader)))
- {
- next = pos->next;
- if (GNUNET_YES == pos->do_transmit)
- {
- GNUNET_assert (pos->size <= size);
- /* do notifications */
- /* FIXME: track if we have *any* client that wants
- * full notifications and only do this if that is
- * actually true */
- if (pos->size <
- GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct
NotifyTrafficMessage))
- {
- memcpy (&ntm[1], &pos[1], pos->size);
- ntm->header.size =
- htons (sizeof (struct NotifyTrafficMessage) +
- sizeof (struct GNUNET_MessageHeader));
- send_to_all_clients (&ntm->header, GNUNET_YES,
- GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
- }
- else
- {
- /* message too large for 'full' notifications, we do at
- * least the 'hdr' type */
- memcpy (&ntm[1], &pos[1], sizeof (struct GNUNET_MessageHeader));
- }
- ntm->header.size =
- htons (sizeof (struct NotifyTrafficMessage) + pos->size);
- send_to_all_clients (&ntm->header, GNUNET_YES,
- GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
-#if DEBUG_HANDSHAKE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Encrypting %u bytes with message of type %u and size %u\n",
- pos->size,
- (unsigned int)
- ntohs (((const struct GNUNET_MessageHeader *)
&pos[1])->type),
- (unsigned int)
- ntohs (((const struct GNUNET_MessageHeader *)
- &pos[1])->size));
-#endif
- /* copy for encrypted transmission */
- memcpy (&buf[ret], &pos[1], pos->size);
- ret += pos->size;
- size -= pos->size;
- *priority += pos->priority;
-#if DEBUG_CORE > 1
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Adding plaintext message of size %u with deadline %llu ms
to batch\n",
- (unsigned int) pos->size,
- (unsigned long long)
- GNUNET_TIME_absolute_get_remaining
(pos->deadline).rel_value);
-#endif
- deadline->abs_value =
- GNUNET_MIN (deadline->abs_value, pos->deadline.abs_value);
- GNUNET_free (pos);
- if (prev == NULL)
- n->messages = next;
- else
- prev->next = next;
- }
- else
- {
- prev = pos;
- }
- pos = next;
- }
-#if DEBUG_CORE > 1
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Deadline for message batch is %llu ms\n",
- GNUNET_TIME_absolute_get_remaining (*deadline).rel_value);
-#endif
- return ret;
-}
-
-
-/**
- * Remove messages with deadlines that have long expired from
- * the queue.
- *
- * @param n neighbour to inspect
- */
-static void
-discard_expired_messages (struct Neighbour *n)
-{
- struct MessageEntry *prev;
- struct MessageEntry *next;
- struct MessageEntry *pos;
- struct GNUNET_TIME_Absolute now;
- struct GNUNET_TIME_Relative delta;
- int disc;
- unsigned int queue_length;
-
- disc = GNUNET_NO;
- now = GNUNET_TIME_absolute_get ();
- prev = NULL;
- queue_length = 0;
- pos = n->messages;
- while (pos != NULL)
- {
- queue_length++;
- next = pos->next;
- delta = GNUNET_TIME_absolute_get_difference (pos->deadline, now);
- if (delta.rel_value > PAST_EXPIRATION_DISCARD_TIME.rel_value)
- {
-#if DEBUG_CORE
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Message is %llu ms past due, discarding.\n",
- delta.rel_value);
-#endif
- if (prev == NULL)
- n->messages = next;
- else
- prev->next = next;
- GNUNET_STATISTICS_update (stats,
- gettext_noop
- ("# messages discarded (expired prior to
transmission)"),
- 1, GNUNET_NO);
- disc = GNUNET_YES;
- GNUNET_free (pos);
- }
- else
- prev = pos;
- pos = next;
- }
- if ( (GNUNET_YES == disc) &&
- (queue_length == MAX_PEER_QUEUE_SIZE) )
- schedule_peer_messages (n);
-}
-
-
-/**
- * Signature of the main function of a task.
- *
- * @param cls closure
- * @param tc context information (why was this task triggered now)
- */
-static void
-retry_plaintext_processing (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct Neighbour *n = cls;
-
- n->retry_plaintext_task = GNUNET_SCHEDULER_NO_TASK;
- process_plaintext_neighbour_queue (n);
-}
-
-
-/**
- * Check if we have plaintext messages for the specified neighbour
- * pending, and if so, consider batching and encrypting them (and
- * then trigger processing of the encrypted queue if needed).
- *
- * @param n neighbour to check.
- */
-static void
-process_plaintext_neighbour_queue (struct Neighbour *n)
-{
- char pbuf[GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE + sizeof (struct
EncryptedMessage)]; /* plaintext */
- size_t used;
- struct EncryptedMessage *em; /* encrypted message */
- struct EncryptedMessage *ph; /* plaintext header */
- struct MessageEntry *me;
- unsigned int priority;
- struct GNUNET_TIME_Absolute deadline;
- struct GNUNET_TIME_Relative retry_time;
- struct GNUNET_CRYPTO_AesInitializationVector iv;
- struct GNUNET_CRYPTO_AuthKey auth_key;
-
- if (n->retry_plaintext_task != GNUNET_SCHEDULER_NO_TASK)
- {
- GNUNET_SCHEDULER_cancel (n->retry_plaintext_task);
- n->retry_plaintext_task = GNUNET_SCHEDULER_NO_TASK;
- }
- switch (n->status)
- {
- case PEER_STATE_DOWN:
- send_key (n);
-#if DEBUG_CORE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Not yet connected to `%4s', deferring processing of plaintext
messages.\n",
- GNUNET_i2s (&n->peer));
-#endif
- return;
- case PEER_STATE_KEY_SENT:
- if (n->retry_set_key_task == GNUNET_SCHEDULER_NO_TASK)
- n->retry_set_key_task =
- GNUNET_SCHEDULER_add_delayed (n->set_key_retry_frequency,
- &set_key_retry_task, n);
-#if DEBUG_CORE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Not yet connected to `%4s', deferring processing of plaintext
messages.\n",
- GNUNET_i2s (&n->peer));
-#endif
- return;
- case PEER_STATE_KEY_RECEIVED:
- if (n->retry_set_key_task == GNUNET_SCHEDULER_NO_TASK)
- n->retry_set_key_task =
- GNUNET_SCHEDULER_add_delayed (n->set_key_retry_frequency,
- &set_key_retry_task, n);
-#if DEBUG_CORE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Not yet connected to `%4s', deferring processing of plaintext
messages.\n",
- GNUNET_i2s (&n->peer));
-#endif
- return;
- case PEER_STATE_KEY_CONFIRMED:
- /* ready to continue */
- break;
- }
- discard_expired_messages (n);
- if (n->messages == NULL)
- {
-#if DEBUG_CORE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Plaintext message queue for `%4s' is empty.\n",
- GNUNET_i2s (&n->peer));
-#endif
- return; /* no pending messages */
- }
- if (n->encrypted_head != NULL)
- {
-#if DEBUG_CORE > 2
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Encrypted message queue for `%4s' is still full, delaying
plaintext processing.\n",
- GNUNET_i2s (&n->peer));
-#endif
- return; /* wait for messages already encrypted to be
- * processed first! */
- }
- ph = (struct EncryptedMessage *) pbuf;
- deadline = GNUNET_TIME_UNIT_FOREVER_ABS;
- priority = 0;
- used = sizeof (struct EncryptedMessage);
- used +=
- batch_message (n, &pbuf[used],
- GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE, &deadline,
- &retry_time, &priority);
- if (used == sizeof (struct EncryptedMessage))
- {
-#if DEBUG_CORE > 1
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "No messages selected for transmission to `%4s' at this time,
will try again later.\n",
- GNUNET_i2s (&n->peer));
-#endif
- /* no messages selected for sending, try again later... */
- n->retry_plaintext_task =
- GNUNET_SCHEDULER_add_delayed (retry_time, &retry_plaintext_processing,
- n);
- return;
- }
-#if DEBUG_CORE_QUOTA
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Sending %u b/s as new limit to peer `%4s'\n",
- (unsigned int) ntohl (n->bw_in.value__), GNUNET_i2s (&n->peer));
-#endif
- ph->iv_seed =
- htonl (GNUNET_CRYPTO_random_u32
- (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX));
- ph->sequence_number = htonl (++n->last_sequence_number_sent);
- ph->inbound_bw_limit = n->bw_in;
- ph->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
-
- /* setup encryption message header */
- me = GNUNET_malloc (sizeof (struct MessageEntry) + used);
- me->deadline = deadline;
- me->priority = priority;
- me->size = used;
- em = (struct EncryptedMessage *) &me[1];
- em->header.size = htons (used);
- em->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE);
- em->iv_seed = ph->iv_seed;
- derive_iv (&iv, &n->encrypt_key, ph->iv_seed, &n->peer);
- /* encrypt */
-#if DEBUG_HANDSHAKE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Encrypting %u bytes of plaintext messages for `%4s' for
transmission in %llums.\n",
- (unsigned int) used - ENCRYPTED_HEADER_SIZE,
- GNUNET_i2s (&n->peer),
- (unsigned long long)
- GNUNET_TIME_absolute_get_remaining (deadline).rel_value);
-#endif
- GNUNET_assert (GNUNET_OK ==
- do_encrypt (n, &iv, &ph->sequence_number,
&em->sequence_number,
- used - ENCRYPTED_HEADER_SIZE));
- derive_auth_key (&auth_key, &n->encrypt_key, ph->iv_seed,
- n->encrypt_key_created);
- GNUNET_CRYPTO_hmac (&auth_key, &em->sequence_number,
- used - ENCRYPTED_HEADER_SIZE, &em->hmac);
-#if DEBUG_HANDSHAKE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Authenticated %u bytes of ciphertext %u: `%s'\n",
- used - ENCRYPTED_HEADER_SIZE,
- GNUNET_CRYPTO_crc32_n (&em->sequence_number,
- used - ENCRYPTED_HEADER_SIZE),
- GNUNET_h2s (&em->hmac));
-#endif
- /* append to transmission list */
- GNUNET_CONTAINER_DLL_insert_after (n->encrypted_head, n->encrypted_tail,
- n->encrypted_tail, me);
- process_encrypted_neighbour_queue (n);
- schedule_peer_messages (n);
-}
-
Modified: gnunet/src/core/gnunet-service-core_sessions.c
===================================================================
--- gnunet/src/core/gnunet-service-core_sessions.c 2011-10-06 09:02:48 UTC
(rev 17241)
+++ gnunet/src/core/gnunet-service-core_sessions.c 2011-10-06 11:01:23 UTC
(rev 17242)
@@ -584,7 +584,526 @@
}
+
+
+
/**
+ * Select messages for transmission. This heuristic uses a combination
+ * of earliest deadline first (EDF) scheduling (with bounded horizon)
+ * and priority-based discard (in case no feasible schedule exist) and
+ * speculative optimization (defer any kind of transmission until
+ * we either create a batch of significant size, 25% of max, or until
+ * we are close to a deadline). Furthermore, when scheduling the
+ * heuristic also packs as many messages into the batch as possible,
+ * starting with those with the earliest deadline. Yes, this is fun.
+ *
+ * @param n neighbour to select messages from
+ * @param size number of bytes to select for transmission
+ * @param retry_time set to the time when we should try again
+ * (only valid if this function returns zero)
+ * @return number of bytes selected, or 0 if we decided to
+ * defer scheduling overall; in that case, retry_time is set.
+ */
+static size_t
+select_messages (struct Neighbour *n, size_t size,
+ struct GNUNET_TIME_Relative *retry_time)
+{
+ struct MessageEntry *pos;
+ struct MessageEntry *min;
+ struct MessageEntry *last;
+ unsigned int min_prio;
+ struct GNUNET_TIME_Absolute t;
+ struct GNUNET_TIME_Absolute now;
+ struct GNUNET_TIME_Relative delta;
+ uint64_t avail;
+ struct GNUNET_TIME_Relative slack; /* how long could we wait before
missing deadlines? */
+ size_t off;
+ uint64_t tsize;
+ unsigned int queue_size;
+ int discard_low_prio;
+
+ GNUNET_assert (NULL != n->messages);
+ now = GNUNET_TIME_absolute_get ();
+ /* last entry in linked list of messages processed */
+ last = NULL;
+ /* should we remove the entry with the lowest
+ * priority from consideration for scheduling at the
+ * end of the loop? */
+ queue_size = 0;
+ tsize = 0;
+ pos = n->messages;
+ while (pos != NULL)
+ {
+ queue_size++;
+ tsize += pos->size;
+ pos = pos->next;
+ }
+ discard_low_prio = GNUNET_YES;
+ while (GNUNET_YES == discard_low_prio)
+ {
+ min = NULL;
+ min_prio = UINT_MAX;
+ discard_low_prio = GNUNET_NO;
+ /* calculate number of bytes available for transmission at time "t" */
+ avail = GNUNET_BANDWIDTH_tracker_get_available (&n->available_send_window);
+ t = now;
+ /* how many bytes have we (hypothetically) scheduled so far */
+ off = 0;
+ /* maximum time we can wait before transmitting anything
+ * and still make all of our deadlines */
+ slack = GNUNET_TIME_UNIT_FOREVER_REL;
+ pos = n->messages;
+ /* note that we use "*2" here because we want to look
+ * a bit further into the future; much more makes no
+ * sense since new message might be scheduled in the
+ * meantime... */
+ while ((pos != NULL) && (off < size * 2))
+ {
+ if (pos->do_transmit == GNUNET_YES)
+ {
+ /* already removed from consideration */
+ pos = pos->next;
+ continue;
+ }
+ if (discard_low_prio == GNUNET_NO)
+ {
+ delta = GNUNET_TIME_absolute_get_difference (t, pos->deadline);
+ if (delta.rel_value > 0)
+ {
+ // FIXME: HUH? Check!
+ t = pos->deadline;
+ avail +=
+ GNUNET_BANDWIDTH_value_get_available_until (n->bw_out, delta);
+ }
+ if (avail < pos->size)
+ {
+ // FIXME: HUH? Check!
+ discard_low_prio = GNUNET_YES; /* we could not schedule this
one! */
+ }
+ else
+ {
+ avail -= pos->size;
+ /* update slack, considering both its absolute deadline
+ * and relative deadlines caused by other messages
+ * with their respective load */
+ slack =
+ GNUNET_TIME_relative_min (slack,
+ GNUNET_BANDWIDTH_value_get_delay_for
+ (n->bw_out, avail));
+ if (pos->deadline.abs_value <= now.abs_value)
+ {
+ /* now or never */
+ slack = GNUNET_TIME_UNIT_ZERO;
+ }
+ else if (GNUNET_YES == pos->got_slack)
+ {
+ /* should be soon now! */
+ slack =
+ GNUNET_TIME_relative_min (slack,
+ GNUNET_TIME_absolute_get_remaining
+ (pos->slack_deadline));
+ }
+ else
+ {
+ slack =
+ GNUNET_TIME_relative_min (slack,
+ GNUNET_TIME_absolute_get_difference
+ (now, pos->deadline));
+ pos->got_slack = GNUNET_YES;
+ pos->slack_deadline =
+ GNUNET_TIME_absolute_min (pos->deadline,
+ GNUNET_TIME_relative_to_absolute
+ (GNUNET_CONSTANTS_MAX_CORK_DELAY));
+ }
+ }
+ }
+ off += pos->size;
+ t = GNUNET_TIME_absolute_max (pos->deadline, t); // HUH? Check!
+ if (pos->priority <= min_prio)
+ {
+ /* update min for discard */
+ min_prio = pos->priority;
+ min = pos;
+ }
+ pos = pos->next;
+ }
+ if (discard_low_prio)
+ {
+ GNUNET_assert (min != NULL);
+ /* remove lowest-priority entry from consideration */
+ min->do_transmit = GNUNET_YES; /* means: discard (for now) */
+ }
+ last = pos;
+ }
+ /* guard against sending "tiny" messages with large headers without
+ * urgent deadlines */
+ if ((slack.rel_value > GNUNET_CONSTANTS_MAX_CORK_DELAY.rel_value) &&
+ (size > 4 * off) && (queue_size <= MAX_PEER_QUEUE_SIZE - 2))
+ {
+ /* less than 25% of message would be filled with deadlines still
+ * being met if we delay by one second or more; so just wait for
+ * more data; but do not wait longer than 1s (since we don't want
+ * to delay messages for a really long time either). */
+ *retry_time = GNUNET_CONSTANTS_MAX_CORK_DELAY;
+ /* reset do_transmit values for next time */
+ while (pos != last)
+ {
+ pos->do_transmit = GNUNET_NO;
+ pos = pos->next;
+ }
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop
+ ("# transmissions delayed due to corking"), 1,
+ GNUNET_NO);
+#if DEBUG_CORE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Deferring transmission for %llums due to underfull message
buffer size (%u/%u)\n",
+ (unsigned long long) retry_time->rel_value, (unsigned int) off,
+ (unsigned int) size);
+#endif
+ return 0;
+ }
+ /* select marked messages (up to size) for transmission */
+ off = 0;
+ pos = n->messages;
+ while (pos != last)
+ {
+ if ((pos->size <= size) && (pos->do_transmit == GNUNET_NO))
+ {
+ pos->do_transmit = GNUNET_YES; /* mark for transmission */
+ off += pos->size;
+ size -= pos->size;
+#if DEBUG_CORE > 1
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Selecting message of size %u for transmission\n",
+ (unsigned int) pos->size);
+#endif
+ }
+ else
+ {
+#if DEBUG_CORE > 1
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Not selecting message of size %u for transmission at this
time (maximum is %u)\n",
+ (unsigned int) pos->size, size);
+#endif
+ pos->do_transmit = GNUNET_NO; /* mark for not transmitting! */
+ }
+ pos = pos->next;
+ }
+#if DEBUG_CORE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Selected %llu/%llu bytes of %u/%u plaintext messages for
transmission to `%4s'.\n",
+ (unsigned long long) off, (unsigned long long) tsize, queue_size,
+ (unsigned int) MAX_PEER_QUEUE_SIZE, GNUNET_i2s (&n->peer));
+#endif
+ return off;
+}
+
+
+/**
+ * Batch multiple messages into a larger buffer.
+ *
+ * @param n neighbour to take messages from
+ * @param buf target buffer
+ * @param size size of buf
+ * @param deadline set to transmission deadline for the result
+ * @param retry_time set to the time when we should try again
+ * (only valid if this function returns zero)
+ * @param priority set to the priority of the batch
+ * @return number of bytes written to buf (can be zero)
+ */
+static size_t
+batch_message (struct Neighbour *n, char *buf, size_t size,
+ struct GNUNET_TIME_Absolute *deadline,
+ struct GNUNET_TIME_Relative *retry_time, unsigned int *priority)
+{
+ char ntmb[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
+ struct NotifyTrafficMessage *ntm = (struct NotifyTrafficMessage *) ntmb;
+ struct MessageEntry *pos;
+ struct MessageEntry *prev;
+ struct MessageEntry *next;
+ size_t ret;
+
+ ret = 0;
+ *priority = 0;
+ *deadline = GNUNET_TIME_UNIT_FOREVER_ABS;
+ *retry_time = GNUNET_TIME_UNIT_FOREVER_REL;
+ if (0 == select_messages (n, size, retry_time))
+ {
+#if DEBUG_CORE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "No messages selected, will try again in %llu ms\n",
+ retry_time->rel_value);
+#endif
+ return 0;
+ }
+ ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND);
+ ntm->ats_count = htonl (0);
+ ntm->ats.type = htonl (0);
+ ntm->ats.value = htonl (0);
+ ntm->peer = n->peer;
+ pos = n->messages;
+ prev = NULL;
+ while ((pos != NULL) && (size >= sizeof (struct GNUNET_MessageHeader)))
+ {
+ next = pos->next;
+ if (GNUNET_YES == pos->do_transmit)
+ {
+ GNUNET_assert (pos->size <= size);
+ /* do notifications */
+ /* FIXME: track if we have *any* client that wants
+ * full notifications and only do this if that is
+ * actually true */
+ if (pos->size <
+ GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct
NotifyTrafficMessage))
+ {
+ memcpy (&ntm[1], &pos[1], pos->size);
+ ntm->header.size =
+ htons (sizeof (struct NotifyTrafficMessage) +
+ sizeof (struct GNUNET_MessageHeader));
+ send_to_all_clients (&ntm->header, GNUNET_YES,
+ GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
+ }
+ else
+ {
+ /* message too large for 'full' notifications, we do at
+ * least the 'hdr' type */
+ memcpy (&ntm[1], &pos[1], sizeof (struct GNUNET_MessageHeader));
+ }
+ ntm->header.size =
+ htons (sizeof (struct NotifyTrafficMessage) + pos->size);
+ send_to_all_clients (&ntm->header, GNUNET_YES,
+ GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
+#if DEBUG_HANDSHAKE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Encrypting %u bytes with message of type %u and size %u\n",
+ pos->size,
+ (unsigned int)
+ ntohs (((const struct GNUNET_MessageHeader *)
&pos[1])->type),
+ (unsigned int)
+ ntohs (((const struct GNUNET_MessageHeader *)
+ &pos[1])->size));
+#endif
+ /* copy for encrypted transmission */
+ memcpy (&buf[ret], &pos[1], pos->size);
+ ret += pos->size;
+ size -= pos->size;
+ *priority += pos->priority;
+#if DEBUG_CORE > 1
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Adding plaintext message of size %u with deadline %llu ms
to batch\n",
+ (unsigned int) pos->size,
+ (unsigned long long)
+ GNUNET_TIME_absolute_get_remaining
(pos->deadline).rel_value);
+#endif
+ deadline->abs_value =
+ GNUNET_MIN (deadline->abs_value, pos->deadline.abs_value);
+ GNUNET_free (pos);
+ if (prev == NULL)
+ n->messages = next;
+ else
+ prev->next = next;
+ }
+ else
+ {
+ prev = pos;
+ }
+ pos = next;
+ }
+#if DEBUG_CORE > 1
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Deadline for message batch is %llu ms\n",
+ GNUNET_TIME_absolute_get_remaining (*deadline).rel_value);
+#endif
+ return ret;
+}
+
+
+/**
+ * Remove messages with deadlines that have long expired from
+ * the queue.
+ *
+ * @param n neighbour to inspect
+ */
+static void
+discard_expired_messages (struct Neighbour *n)
+{
+ struct MessageEntry *prev;
+ struct MessageEntry *next;
+ struct MessageEntry *pos;
+ struct GNUNET_TIME_Absolute now;
+ struct GNUNET_TIME_Relative delta;
+ int disc;
+ unsigned int queue_length;
+
+ disc = GNUNET_NO;
+ now = GNUNET_TIME_absolute_get ();
+ prev = NULL;
+ queue_length = 0;
+ pos = n->messages;
+ while (pos != NULL)
+ {
+ queue_length++;
+ next = pos->next;
+ delta = GNUNET_TIME_absolute_get_difference (pos->deadline, now);
+ if (delta.rel_value > PAST_EXPIRATION_DISCARD_TIME.rel_value)
+ {
+#if DEBUG_CORE
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Message is %llu ms past due, discarding.\n",
+ delta.rel_value);
+#endif
+ if (prev == NULL)
+ n->messages = next;
+ else
+ prev->next = next;
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop
+ ("# messages discarded (expired prior to
transmission)"),
+ 1, GNUNET_NO);
+ disc = GNUNET_YES;
+ GNUNET_free (pos);
+ }
+ else
+ prev = pos;
+ pos = next;
+ }
+ if ( (GNUNET_YES == disc) &&
+ (queue_length == MAX_PEER_QUEUE_SIZE) )
+ schedule_peer_messages (n);
+}
+
+
+/**
+ * Signature of the main function of a task.
+ *
+ * @param cls closure
+ * @param tc context information (why was this task triggered now)
+ */
+static void
+retry_plaintext_processing (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct Neighbour *n = cls;
+
+ n->retry_plaintext_task = GNUNET_SCHEDULER_NO_TASK;
+ process_plaintext_neighbour_queue (n);
+}
+
+
+/**
+ * Check if we have plaintext messages for the specified neighbour
+ * pending, and if so, consider batching and encrypting them (and
+ * then trigger processing of the encrypted queue if needed).
+ *
+ * @param n neighbour to check.
+ */
+static void
+process_plaintext_neighbour_queue (struct Neighbour *n)
+{
+ char pbuf[GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE + sizeof (struct
EncryptedMessage)]; /* plaintext */
+ size_t used;
+ struct EncryptedMessage *em; /* encrypted message */
+ struct EncryptedMessage *ph; /* plaintext header */
+ struct MessageEntry *me;
+ unsigned int priority;
+ struct GNUNET_TIME_Absolute deadline;
+ struct GNUNET_TIME_Relative retry_time;
+ struct GNUNET_CRYPTO_AesInitializationVector iv;
+ struct GNUNET_CRYPTO_AuthKey auth_key;
+
+ if (n->retry_plaintext_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (n->retry_plaintext_task);
+ n->retry_plaintext_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ switch (n->status)
+ {
+ case PEER_STATE_DOWN:
+ send_key (n);
+#if DEBUG_CORE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Not yet connected to `%4s', deferring processing of plaintext
messages.\n",
+ GNUNET_i2s (&n->peer));
+#endif
+ return;
+ case PEER_STATE_KEY_SENT:
+ if (n->retry_set_key_task == GNUNET_SCHEDULER_NO_TASK)
+ n->retry_set_key_task =
+ GNUNET_SCHEDULER_add_delayed (n->set_key_retry_frequency,
+ &set_key_retry_task, n);
+#if DEBUG_CORE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Not yet connected to `%4s', deferring processing of plaintext
messages.\n",
+ GNUNET_i2s (&n->peer));
+#endif
+ return;
+ case PEER_STATE_KEY_RECEIVED:
+ if (n->retry_set_key_task == GNUNET_SCHEDULER_NO_TASK)
+ n->retry_set_key_task =
+ GNUNET_SCHEDULER_add_delayed (n->set_key_retry_frequency,
+ &set_key_retry_task, n);
+#if DEBUG_CORE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Not yet connected to `%4s', deferring processing of plaintext
messages.\n",
+ GNUNET_i2s (&n->peer));
+#endif
+ return;
+ case PEER_STATE_KEY_CONFIRMED:
+ /* ready to continue */
+ break;
+ }
+ discard_expired_messages (n);
+ if (n->messages == NULL)
+ {
+#if DEBUG_CORE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Plaintext message queue for `%4s' is empty.\n",
+ GNUNET_i2s (&n->peer));
+#endif
+ return; /* no pending messages */
+ }
+ if (n->encrypted_head != NULL)
+ {
+#if DEBUG_CORE > 2
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Encrypted message queue for `%4s' is still full, delaying
plaintext processing.\n",
+ GNUNET_i2s (&n->peer));
+#endif
+ return; /* wait for messages already encrypted to be
+ * processed first! */
+ }
+ ph = (struct EncryptedMessage *) pbuf;
+ deadline = GNUNET_TIME_UNIT_FOREVER_ABS;
+ priority = 0;
+ used = sizeof (struct EncryptedMessage);
+ used +=
+ batch_message (n, &pbuf[used],
+ GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE, &deadline,
+ &retry_time, &priority);
+ if (used == sizeof (struct EncryptedMessage))
+ {
+#if DEBUG_CORE > 1
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "No messages selected for transmission to `%4s' at this time,
will try again later.\n",
+ GNUNET_i2s (&n->peer));
+#endif
+ /* no messages selected for sending, try again later... */
+ n->retry_plaintext_task =
+ GNUNET_SCHEDULER_add_delayed (retry_time, &retry_plaintext_processing,
+ n);
+ return;
+ }
+ GSC_KX_encrypt_and_transmit (n->kx,
+ &pbuf[struct EncryptedMessage],
+ used - sizeof (struct EncryptedMessage));
+ schedule_peer_messages (n);
+}
+
+
+
+
+/**
* Check if we have encrypted messages for the specified neighbour
* pending, and if so, check with the transport about sending them
* out.
Modified: gnunet/src/core/gnunet-service-core_typemap.c
===================================================================
--- gnunet/src/core/gnunet-service-core_typemap.c 2011-10-06 09:02:48 UTC
(rev 17241)
+++ gnunet/src/core/gnunet-service-core_typemap.c 2011-10-06 11:01:23 UTC
(rev 17242)
@@ -1,5 +1,15 @@
/**
+ * A type map describing which messages a given neighbour is able
+ * to process.
+ */
+struct GSC_TypeMap
+{
+ uint32_t bits[(UINT16_MAX + 1) / 32];
+};
+
+
+/**
* Bitmap of message types this peer is able to handle.
*/
static uint32_t my_type_map[(UINT16_MAX + 1) / 32];
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] r17242 - gnunet/src/core,
gnunet <=