gnunet-svn
[Top][All Lists]
Advanced

[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];




reply via email to

[Prev in Thread] Current Thread [Next in Thread]