gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [gnunet] 01/02: more work on TCP communicator


From: gnunet
Subject: [GNUnet-SVN] [gnunet] 01/02: more work on TCP communicator
Date: Mon, 28 Jan 2019 11:05:13 +0100

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository gnunet.

commit 64483767341fc741ea68249335ac1914c5a6cf1c
Author: Christian Grothoff <address@hidden>
AuthorDate: Mon Jan 28 05:50:12 2019 +0100

    more work on TCP communicator
---
 src/include/gnunet_crypto_lib.h          |   4 +-
 src/include/gnunet_protocols.h           |  17 +-
 src/include/gnunet_signatures.h          |   5 +
 src/transport/gnunet-communicator-tcp.c  | 583 +++++++++++++++++++++++++++----
 src/transport/gnunet-communicator-unix.c |   2 +-
 5 files changed, 545 insertions(+), 66 deletions(-)

diff --git a/src/include/gnunet_crypto_lib.h b/src/include/gnunet_crypto_lib.h
index 6342862eb..6a9eddd7c 100644
--- a/src/include/gnunet_crypto_lib.h
+++ b/src/include/gnunet_crypto_lib.h
@@ -740,8 +740,8 @@ GNUNET_CRYPTO_hash_context_abort (struct GNUNET_HashContext 
*hc);
  */
 void
 GNUNET_CRYPTO_hmac_raw (const void *key, size_t key_len,
-                    const void *plaintext, size_t plaintext_len,
-                    struct GNUNET_HashCode *hmac);
+                       const void *plaintext, size_t plaintext_len,
+                       struct GNUNET_HashCode *hmac);
 
 
 /**
diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h
index 1cd06de8d..409356d77 100644
--- a/src/include/gnunet_protocols.h
+++ b/src/include/gnunet_protocols.h
@@ -3219,7 +3219,22 @@ extern "C"
 
 
 /**
- * Next available: 1450
+ * TCP communicator rekey message.
+ */
+#define GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_REKEY 1450
+
+/**
+ * TCP communicator payload box
+ */
+#define GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_BOX 1451
+
+/**
+ * TCP communicator end of stream.
+ */ 
+#define GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_FINISH 1452
+
+/**
+ * Next available: 1500
  */
 
 
diff --git a/src/include/gnunet_signatures.h b/src/include/gnunet_signatures.h
index 738a414ab..4f4d546ff 100644
--- a/src/include/gnunet_signatures.h
+++ b/src/include/gnunet_signatures.h
@@ -207,6 +207,11 @@ extern "C"
  */ 
 #define GNUNET_SIGNATURE_COMMUNICATOR_TCP_HANDSHAKE 31
 
+/**
+ * Signature used by TCP communicator rekey.
+ */ 
+#define GNUNET_SIGNATURE_COMMUNICATOR_TCP_REKEY 32
+
 #if 0                           /* keep Emacsens' auto-indent happy */
 {
 #endif
diff --git a/src/transport/gnunet-communicator-tcp.c 
b/src/transport/gnunet-communicator-tcp.c
index 6e3faa44a..5a397c296 100644
--- a/src/transport/gnunet-communicator-tcp.c
+++ b/src/transport/gnunet-communicator-tcp.c
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet
-     Copyright (C) 2010-2014, 2018 GNUnet e.V.
+     Copyright (C) 2010-2014, 2018, 2019 GNUnet e.V.
 
      GNUnet is free software: you can redistribute it and/or modify it
      under the terms of the GNU Affero General Public License as published
@@ -33,6 +33,7 @@
 #include "platform.h"
 #include "gnunet_util_lib.h"
 #include "gnunet_protocols.h"
+#include "gnunet_signatures.h"
 #include "gnunet_constants.h"
 #include "gnunet_nt_lib.h"
 #include "gnunet_statistics_service.h"
@@ -48,6 +49,23 @@
  */
 #define DEFAULT_MAX_QUEUE_LENGTH 8
 
+/**
+ * Size of our IO buffers for ciphertext data. Must be at
+ * least UINT_MAX + sizeof (struct TCPBox).
+ */
+#define BUF_SIZE (2 * 64 * 1024 + sizeof (struct TCPBox))
+
+/**
+ * How often do we rekey based on time (at least)
+ */ 
+#define REKEY_TIME_INTERVAL GNUNET_TIME_UNIT_DAYS
+
+/**
+ * How often do we rekey based on number of bytes transmitted?
+ * (additionally randomized).
+ */ 
+#define REKEY_MAX_BYTES (1024LLU * 1024 * 1024 * 4LLU)
+
 /**
  * Address prefix used by the communicator.
  */
@@ -60,19 +78,6 @@
 
 GNUNET_NETWORK_STRUCT_BEGIN
 
-/**
- * TCP initial bytes on the wire (in either direction), used to 
- * establish a shared secret.
- */
-struct TCPHandshake
-{
-  /**
-   * First bytes: ephemeral key for KX.
-   */
-  struct GNUNET_CRYPTO_EcdhePublicKey ephemeral;
-
-};
-
 
 /**
  * Signature we use to verify that the ephemeral key was really chosen by
@@ -139,7 +144,10 @@ struct TCPBox
 {
   
   /**
-   * Type is #GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_BOX.
+   * Type is #GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_BOX.  Warning: the
+   * header size EXCLUDES the size of the `struct TCPBox`. We usually
+   * never do this, but here the payload may truly be 64k *after* the
+   * TCPBox (as we have no MTU)!!
    */ 
   struct GNUNET_MessageHeader header;
 
@@ -153,7 +161,8 @@ struct TCPBox
    */ 
   struct GNUNET_ShortHashCode hmac;
 
-  /* followed by as may bytes of payload as indicated in @e header */
+  /* followed by as may bytes of payload as indicated in @e header,
+     excluding the TCPBox itself! */
   
 };
 
@@ -186,7 +195,7 @@ struct TCPRekey
   struct GNUNET_CRYPTO_EcdhePublicKey ephemeral;
   
   /**
-   * Sender's signature of type #GNUNET_SIGNATURE_COMMUNICATOR_TCP_HANDSHAKE
+   * Sender's signature of type #GNUNET_SIGNATURE_COMMUNICATOR_TCP_REKEY
    */
   struct GNUNET_CRYPTO_EddsaSignature sender_sig;
 
@@ -260,10 +269,16 @@ struct Queue
   struct GNUNET_HashCode in_hmac;
 
   /**
-   * Shared secret for HMAC generation on outgoing data.
+   * Shared secret for HMAC generation on outgoing data, ratcheted after
+   * each operation.
    */ 
   struct GNUNET_HashCode out_hmac;
 
+  /**
+   * Our ephemeral key. Stored here temporarily during rekeying / key 
generation.
+   */
+  struct GNUNET_CRYPTO_EcdhePrivateKey ephemeral;
+  
   /**
    * ID of read task for this connection.
    */
@@ -296,12 +311,6 @@ struct Queue
    */
   socklen_t address_len;
 
-  /**
-   * Message currently scheduled for transmission, non-NULL if and only
-   * if this queue is in the #queue_head DLL.
-   */
-  const struct GNUNET_MessageHeader *msg;
-
   /**
    * Message queue we are providing for the #ch.
    */
@@ -317,6 +326,50 @@ struct Queue
    */
   unsigned long long bytes_in_queue;
 
+  /**
+   * Buffer for reading ciphertext from network into.
+   */
+  char cread_buf[BUF_SIZE];
+
+  /**
+   * buffer for writing ciphertext to network.
+   */
+  char cwrite_buf[BUF_SIZE];
+
+  /**
+   * Plaintext buffer for decrypted plaintext.
+   */
+  char pread_buf[UINT16_MAX + 1 + sizeof (struct TCPBox)];
+
+  /**
+   * Plaintext buffer for messages to be encrypted.
+   */
+  char pwrite_buf[UINT16_MAX + 1 + sizeof (struct TCPBox)];
+  
+  /**
+   * At which offset in the ciphertext read buffer should we
+   * append more ciphertext for transmission next?
+   */
+  size_t cread_off;
+
+  /**
+   * At which offset in the ciphertext write buffer should we
+   * append more ciphertext from reading next?
+   */
+  size_t cwrite_off;
+  
+  /**
+   * At which offset in the plaintext input buffer should we
+   * append more plaintext from decryption next?
+   */
+  size_t pread_off;
+  
+  /**
+   * At which offset in the plaintext output buffer should we
+   * append more plaintext for encryption next?
+   */
+  size_t pwrite_off;
+
   /**
    * Timeout for this queue.
    */
@@ -326,7 +379,23 @@ struct Queue
    * Which network type does this queue use?
    */
   enum GNUNET_NetworkType nt;
+
+  /**
+   * Is MQ awaiting a #GNUNET_MQ_impl_send_continue() call?
+   */
+  int mq_awaits_continue;
   
+  /**
+   * Did we enqueue a finish message and are closing down the queue?
+   */
+  int finishing;
+
+  /**
+   * #GNUNET_YES after #inject_key() placed the rekey message into the
+   * plaintext buffer. Once the plaintext buffer is drained, this
+   * means we must switch to the new key material.
+   */
+  int rekey_state;
 };
 
 
@@ -370,6 +439,21 @@ static struct GNUNET_NETWORK_Handle *listen_sock;
  */
 static struct GNUNET_TRANSPORT_AddressIdentifier *ai;
 
+/**
+ * Our public key.
+ */
+static struct GNUNET_PeerIdentity my_identity;
+
+/**
+ * Our private key.
+ */
+static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
+
+/**
+ * Our configuration.
+ */
+static const struct GNUNET_CONFIGURATION_Handle *cfg;
+
 
 /**
  * We have been notified that our listen socket has something to
@@ -407,7 +491,7 @@ queue_destroy (struct Queue *queue)
                                                       &queue->target,
                                                       queue));
   GNUNET_STATISTICS_set (stats,
-                        "# UNIX queues active",
+                        "# queues active",
                         GNUNET_CONTAINER_multipeermap_size (queue_map),
                         GNUNET_NO);
   if (NULL != queue->read_task)
@@ -434,6 +518,52 @@ queue_destroy (struct Queue *queue)
 }
 
 
+/**
+ * Compute @a mac over @a buf, and ratched the @a hmac_secret.
+ *
+ * @param[in,out] hmac_secret secret for HMAC calculation
+ * @param buf buffer to MAC
+ * @param buf_size number of bytes in @a buf
+ * @param smac[out] where to write the HMAC
+ */
+static void
+hmac (struct GNUNET_HashCode *hmac_secret,
+      const void *buf,
+      size_t buf_size,
+      struct GNUNET_ShortHashCode *smac)
+{
+  struct GNUNET_HashCode mac;
+
+  GNUNET_CRYPTO_hmac_raw (hmac_secret,
+                         sizeof (struct GNUNET_HashCode),
+                         buf,
+                         buf_size,
+                         &mac);
+  /* truncate to `struct GNUNET_ShortHashCode` */
+  memcpy (smac,
+         &mac,
+         sizeof (struct GNUNET_ShortHashCode));
+  /* ratchet hmac key */
+  GNUNET_CRYPTO_hash (hmac_secret,
+                     sizeof (struct GNUNET_HashCode),
+                     hmac_secret);
+}
+
+
+/**
+ * Append a 'finish' message to the outgoing transmission. Once the
+ * finish has been transmitted, destroy the queue.
+ *
+ * @param queue queue to shut down nicely
+ */
+static void
+queue_finish (struct Queue *queue)
+{
+  // FIXME: try to send 'finish' message first!?
+  queue_destroy (queue);
+}
+
+
 /**
  * Queue read task. If we hit the timeout, disconnect it
  *
@@ -444,12 +574,32 @@ queue_read (void *cls)
 {
   struct Queue *queue = cls;
   struct GNUNET_TIME_Relative left;
+  ssize_t rcvd;
 
   queue->read_task = NULL;
-  /* CHECK IF READ-ready, then perform read! */
+  /* FIXME: perform read! */
+  rcvd = GNUNET_NETWORK_socket_recv (queue->sock,
+                                    &queue->cread_buf[queue->cread_off],
+                                    BUF_SIZE - queue->cread_off);
+  if (-1 == rcvd)
+  {
+    // FIXME: error handling...
+  }
+  if (0 != rcvd)
+    /* update queue timeout */
+  queue->cread_off += rcvd;
+  if (queue->pread_off < sizeof (queue->pread_buf))
+  {
+    /* FIXME: decrypt */
   
+    /* FIXME: check plaintext for complete messages, if complete, hand to CORE 
*/
+    /* FIXME: CORE flow control: suspend doing more until CORE has ACKed */
+  }
+  
+  if (BUF_SIZE == queue->cread_off)
+    return; /* buffer full, suspend reading */
   left = GNUNET_TIME_absolute_get_remaining (queue->timeout);
-  if (0 != left.rel_value_us)
+  if (0 != left.rel_value_us) 
   {
     /* not actually our turn yet, but let's at least update
        the monitor, it may think we're about to die ... */
@@ -458,6 +608,7 @@ queue_read (void *cls)
                                       queue->sock,
                                       &queue_read,
                                       queue);
+
     return;
   }
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -465,8 +616,7 @@ queue_read (void *cls)
              queue,
              GNUNET_STRINGS_relative_time_to_string 
(GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
                                                      GNUNET_YES));
-  // FIXME: try to send 'finish' message first!?
-  queue_destroy (queue);
+  queue_finish (queue);
 }
 
 
@@ -505,6 +655,175 @@ tcp_address_to_sockaddr (const char *bindto,
 }
 
 
+/**
+ * Setup @a cipher based on shared secret @a dh and decrypting
+ * peer @a pid.
+ *
+ * @param dh shared secret
+ * @param pid decrypting peer's identity
+ * @param cipher[out] cipher to initialize
+ * @param hmac_key[out] HMAC key to initialize
+ */
+static void
+setup_cipher (const struct GNUNET_HashCode *dh,
+             const struct GNUNET_PeerIdentity *pid,
+             gcry_cipher_hd_t *cipher,
+             struct GNUNET_HashCode *hmac_key)
+{
+  char key[256/8];
+  char ctr[128/8];
+
+  gcry_cipher_open (cipher,
+                   GCRY_CIPHER_AES256 /* low level: go for speed */,
+                   GCRY_CIPHER_MODE_CTR,
+                   0 /* flags */);
+  GNUNET_assert (GNUNET_YES ==
+                GNUNET_CRYPTO_kdf (key,
+                                   sizeof (key),
+                                   "TCP-key",
+                                   strlen ("TCP-key"),
+                                   dh,
+                                   sizeof (*dh),
+                                   pid,
+                                   sizeof (*pid),
+                                   NULL, 0));
+  gcry_cipher_setkey (*cipher,
+                     key,
+                     sizeof (key));
+  GNUNET_assert (GNUNET_YES ==
+                GNUNET_CRYPTO_kdf (ctr,
+                                   sizeof (ctr),
+                                   "TCP-ctr",
+                                   strlen ("TCP-ctr"),
+                                   dh,
+                                   sizeof (*dh),
+                                   pid,
+                                   sizeof (*pid),
+                                   NULL, 0));
+  gcry_cipher_setctr (*cipher,
+                     ctr,
+                     sizeof (ctr));
+  GNUNET_assert (GNUNET_YES ==
+                GNUNET_CRYPTO_kdf (hmac_key,
+                                   sizeof (struct GNUNET_HashCode),
+                                   "TCP-hmac",
+                                   strlen ("TCP-hmac"),
+                                   dh,
+                                   sizeof (*dh),
+                                   pid,
+                                   sizeof (*pid),
+                                   NULL, 0));
+}
+
+
+/**
+ * Setup cipher of @a queue for decryption.
+ *
+ * @param ephemeral ephemeral key we received from the other peer
+ * @param queue[in,out] queue to initialize decryption cipher for
+ */
+static void
+setup_in_cipher (const struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral,
+                struct Queue *queue)
+{
+  struct GNUNET_HashCode dh;
+  
+  GNUNET_CRYPTO_eddsa_ecdh (my_private_key,
+                           ephemeral,
+                           &dh);
+  setup_cipher (&dh,
+               &my_identity,
+               &queue->in_cipher,
+               &queue->in_hmac);
+}
+               
+
+/**
+ * Setup cipher for outgoing data stream based on target and
+ * our ephemeral private key.
+ *
+ * @param queue queue to setup outgoing (encryption) cipher for
+ */
+static void
+setup_out_cipher (struct Queue *queue)
+{
+  struct GNUNET_HashCode dh;
+  
+  GNUNET_CRYPTO_ecdh_eddsa (&queue->ephemeral,
+                           &queue->target.public_key,
+                           &dh);
+  /* we don't need the private key anymore, drop it! */
+  memset (&queue->ephemeral,
+         0,
+         sizeof (queue->ephemeral));
+  setup_cipher (&dh,
+               &queue->target,
+               &queue->out_cipher,
+               &queue->out_hmac);
+  
+  queue->rekey_time = GNUNET_TIME_relative_to_absolute (REKEY_TIME_INTERVAL);
+  queue->rekey_left_bytes = GNUNET_CRYPTO_random_u64 
(GNUNET_CRYPTO_QUALITY_WEAK,
+                                                     REKEY_MAX_BYTES);
+}
+
+
+/**
+ * Inject a `struct TCPRekey` message into the queue's plaintext
+ * buffer.
+ *
+ * @param queue queue to perform rekeying on
+ */ 
+static void
+inject_rekey (struct Queue *queue)
+{
+  struct TCPRekey rekey;
+  struct TcpHandshakeSignature thp;
+  
+  GNUNET_assert (0 == queue->pwrite_off);
+  memset (&rekey,
+         0,
+         sizeof (rekey));
+  GNUNET_assert (GNUNET_OK ==
+                GNUNET_CRYPTO_ecdhe_key_create2 (&queue->ephemeral));
+  rekey.header.type = ntohs (GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_REKEY);
+  rekey.header.size = ntohs (sizeof (rekey));
+  GNUNET_CRYPTO_ecdhe_key_get_public (&queue->ephemeral,
+                                     &rekey.ephemeral);
+  rekey.monotonic_time = GNUNET_TIME_absolute_hton 
(GNUNET_TIME_absolute_get_monotonic (cfg));
+  thp.purpose.purpose = htonl (GNUNET_SIGNATURE_COMMUNICATOR_TCP_REKEY);
+  thp.purpose.size = htonl (sizeof (thp));
+  thp.sender = my_identity;
+  thp.receiver = queue->target;
+  thp.ephemeral = rekey.ephemeral;
+  thp.monotonic_time = rekey.monotonic_time;
+  GNUNET_assert (GNUNET_OK ==
+                GNUNET_CRYPTO_eddsa_sign (my_private_key,
+                                          &thp.purpose,
+                                          &rekey.sender_sig));
+  hmac (&queue->out_hmac,
+       &rekey,
+       sizeof (rekey),
+       &rekey.hmac);
+  memcpy (queue->pwrite_buf,
+         &rekey,
+         sizeof (rekey));
+  queue->rekey_state = GNUNET_YES;
+}
+
+
+/**
+ * We encrypted the rekey message, now update actually swap the key
+ * material and update the key freshness parameters of @a queue.
+ */ 
+static void
+switch_key (struct Queue *queue)
+{
+  queue->rekey_state = GNUNET_NO; 
+  gcry_cipher_close (queue->out_cipher);
+  setup_out_cipher (queue);
+}
+
+
 /**
  * We have been notified that our socket is ready to write.
  * Then reschedule this function to be called again once more is available.
@@ -515,17 +834,68 @@ static void
 queue_write (void *cls)
 {
   struct Queue *queue = cls;
-  const struct GNUNET_MessageHeader *msg = queue->msg;
-  size_t msg_size = ntohs (msg->size);
+  ssize_t sent;
 
   queue->write_task = NULL;
-  /* FIXME: send 'msg' */
-  /* FIXME: check if we have more messages pending */
-  queue->write_task 
-    = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
-                                     queue->sock,
-                                     &queue_write,
-                                     queue);
+  sent = GNUNET_NETWORK_socket_send (queue->sock,
+                                    queue->cwrite_buf,
+                                    queue->cwrite_off);
+  if ( (-1 == sent) &&
+       (EAGAIN != errno) &&
+       (EINTR != errno) )
+  {
+    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                        "send");
+    queue_destroy (queue);
+    return;                     
+  }
+  if (sent > 0)
+  {
+    size_t usent = (size_t) sent;
+
+    memmove (queue->cwrite_buf,
+            &queue->cwrite_buf[sent],
+            queue->cwrite_off - sent);
+    /* FIXME: update queue timeout */ 
+ }
+  /* can we encrypt more? (always encrypt full messages, needed
+     such that #mq_cancel() can work!) */
+  if (queue->cwrite_off + queue->pwrite_off <= BUF_SIZE)
+  {
+    GNUNET_assert (0 ==
+                  gcry_cipher_encrypt (queue->out_cipher,
+                                       &queue->cwrite_buf[queue->cwrite_off],
+                                       queue->pwrite_off,
+                                       queue->pwrite_buf,
+                                       queue->pwrite_off));
+    if (queue->rekey_left_bytes > queue->pwrite_off)
+      queue->rekey_left_bytes -= queue->pwrite_off;
+    else
+      queue->rekey_left_bytes = 0;
+    queue->cwrite_off += queue->pwrite_off;
+    queue->pwrite_off = 0;
+  }
+  if ( (GNUNET_YES == queue->rekey_state) &&
+       (0 == queue->pwrite_off) )
+    switch_key (queue);
+  if ( (0 == queue->pwrite_off) &&
+       ( (0 == queue->rekey_left_bytes) ||
+        (0 == GNUNET_TIME_absolute_get_remaining 
(queue->rekey_time).rel_value_us) ) )
+    inject_rekey (queue);
+  if ( (0 == queue->pwrite_off) &&
+       (! queue->finishing) &&
+       (queue->mq_awaits_continue) )
+  {
+    queue->mq_awaits_continue = GNUNET_NO;
+    GNUNET_MQ_impl_send_continue (queue->mq);
+  }
+  /* do we care to write more? */
+  if (0 < queue->cwrite_off)
+    queue->write_task 
+      = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
+                                       queue->sock,
+                                       &queue_write,
+                                       queue);
 }
 
 
@@ -543,10 +913,25 @@ mq_send (struct GNUNET_MQ_Handle *mq,
         void *impl_state)
 {
   struct Queue *queue = impl_state;
+  uint16_t msize = ntohs (msg->size);
+  struct TCPBox box;
 
   GNUNET_assert (mq == queue->mq);
-  GNUNET_assert (NULL == queue->msg);
-  queue->msg = msg;
+  GNUNET_assert (0 == queue->pread_off);
+  box.header.type = htons (GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_BOX);
+  box.header.size = htons (msize);
+  hmac (&queue->out_hmac,
+       msg,
+       msize,
+       &box.hmac);
+  memcpy (&queue->pread_buf[queue->pread_off],
+         &box,
+         sizeof (box));
+  queue->pread_off += sizeof (box);
+  memcpy (&queue->pread_buf[queue->pread_off],
+         msg,
+         msize);
+  queue->pread_off += msize;
   GNUNET_assert (NULL != queue->sock);
   if (NULL == queue->write_task)
     queue->write_task =
@@ -574,7 +959,7 @@ mq_destroy (struct GNUNET_MQ_Handle *mq,
   if (mq == queue->mq)
   {
     queue->mq = NULL;
-    queue_destroy (queue);
+    queue_finish (queue);
   }
 }
 
@@ -591,14 +976,8 @@ mq_cancel (struct GNUNET_MQ_Handle *mq,
 {
   struct Queue *queue = impl_state;
 
-  GNUNET_assert (NULL != queue->msg);
-  queue->msg = NULL;
-  GNUNET_assert (NULL != queue->write_task);
-  if (1) // FIXME?
-  {
-    GNUNET_SCHEDULER_cancel (queue->write_task);
-    queue->write_task = NULL;
-  }
+  GNUNET_assert (0 != queue->pwrite_off);
+  queue->pwrite_off = 0;
 }
 
 
@@ -618,10 +997,10 @@ mq_error (void *cls,
   struct Queue *queue = cls;
 
   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-             "TCP MQ error in queue to %s: %d\n",
+             "MQ error in queue to %s: %d\n",
              GNUNET_i2s (&queue->target),
              (int) error);
-  queue_destroy (queue);
+  queue_finish (queue);
 }
 
 
@@ -629,7 +1008,8 @@ mq_error (void *cls,
  * Creates a new outbound queue the transport service will use to send
  * data to another peer.
  *
- * @param peer the target peer
+ * @param sock the queue's socket
+ * @param target the target peer
  * @param cs inbound or outbound queue
  * @param in the address
  * @param in_len number of bytes in @a in
@@ -637,6 +1017,7 @@ mq_error (void *cls,
  */
 static struct Queue *
 setup_queue (struct GNUNET_NETWORK_Handle *sock,
+            const struct GNUNET_PeerIdentity *target,
             enum GNUNET_TRANSPORT_ConnectionStatus cs,
             const struct sockaddr *in,
             socklen_t in_len)
@@ -644,7 +1025,7 @@ setup_queue (struct GNUNET_NETWORK_Handle *sock,
   struct Queue *queue;
 
   queue = GNUNET_new (struct Queue);
-  // queue->target = *target; // FIXME: handle case that we don't know the 
target yet!
+  queue->target = *target; 
   queue->address = GNUNET_memdup (in,
                                  in_len);
   queue->address_len = in_len;
@@ -730,12 +1111,9 @@ listen_cb (void *cls);
 static void
 listen_cb (void *cls)
 {
-  char buf[65536] GNUNET_ALIGN;
   struct Queue *queue;
   struct sockaddr_storage in;
   socklen_t addrlen;
-  ssize_t ret;
-  uint16_t msize;
   struct GNUNET_NETWORK_Handle *sock;
 
   listen_task = NULL;
@@ -765,6 +1143,9 @@ listen_cb (void *cls)
                          "accept");
     return;
   }
+#if 0
+  // FIXME: setup proto-queue first here, until we have received the starting
+  // messages!
   queue = setup_queue (sock,
                       GNUNET_TRANSPORT_CS_INBOUND,
                       (struct sockaddr *) &in,
@@ -775,6 +1156,7 @@ listen_cb (void *cls)
                _("Maximum number of TCP connections exceeded, dropping 
incoming connection\n"));
     return;
   }
+#endif
 }
 
 
@@ -804,6 +1186,10 @@ mq_init (void *cls,
   const char *path;
   struct sockaddr *in;
   socklen_t in_len;
+  struct GNUNET_NETWORK_Handle *sock;
+  struct GNUNET_CRYPTO_EcdhePublicKey epub;
+  struct TcpHandshakeSignature ths;
+  struct TCPConfirmation tc;
 
   if (0 != strncmp (address,
                    COMMUNICATOR_ADDRESS_PREFIX "-",
@@ -815,12 +1201,37 @@ mq_init (void *cls,
   path = &address[strlen (COMMUNICATOR_ADDRESS_PREFIX "-")];
   in = tcp_address_to_sockaddr (path,
                                &in_len);
-#if FIXME
-  queue = setup_queue (peer,
+  
+  sock = GNUNET_NETWORK_socket_create (in->sa_family,
+                                      SOCK_STREAM,
+                                      IPPROTO_TCP);
+  if (NULL == sock)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+               "socket(%d) failed: %s",
+               in->sa_family,
+               STRERROR (errno));
+    GNUNET_free (in);
+    return GNUNET_SYSERR;
+  }
+  if (GNUNET_OK !=
+      GNUNET_NETWORK_socket_connect (sock,
+                                    in,
+                                    in_len))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+               "connect to `%s' failed: %s",
+               address,
+               STRERROR (errno));
+    GNUNET_NETWORK_socket_close (sock);
+    GNUNET_free (in);
+    return GNUNET_SYSERR;
+  }
+  queue = setup_queue (sock,
+                      peer,
                       GNUNET_TRANSPORT_CS_OUTBOUND,
                       in,
                       in_len);
-#endif
   GNUNET_free (in);
   if (NULL == queue)
   {
@@ -828,8 +1239,39 @@ mq_init (void *cls,
                "Failed to setup queue to %s at `%s'\n",
                GNUNET_i2s (peer),
                path);
+    GNUNET_NETWORK_socket_close (sock);
     return GNUNET_NO;
   }
+  GNUNET_assert (GNUNET_OK ==
+                GNUNET_CRYPTO_ecdhe_key_create2 (&queue->ephemeral)); 
+  GNUNET_CRYPTO_ecdhe_key_get_public (&queue->ephemeral,
+                                     &epub);
+  setup_out_cipher (queue);
+  memcpy (queue->cwrite_buf,
+         &epub,
+         sizeof (epub));
+  queue->cwrite_off = sizeof (epub);
+  /* compute 'tc' and append in encrypted format to cwrite_buf */
+  tc.sender = my_identity;
+  tc.monotonic_time = GNUNET_TIME_absolute_hton 
(GNUNET_TIME_absolute_get_monotonic (cfg));
+  ths.purpose.purpose = htonl (GNUNET_SIGNATURE_COMMUNICATOR_TCP_HANDSHAKE);
+  ths.purpose.size = htonl (sizeof (ths));
+  ths.sender = my_identity;
+  ths.receiver = queue->target;
+  ths.ephemeral = epub;
+  ths.monotonic_time = tc.monotonic_time;
+  GNUNET_assert (GNUNET_OK ==
+                GNUNET_CRYPTO_eddsa_sign (my_private_key,
+                                          &ths.purpose,
+                                          &tc.sender_sig));
+  GNUNET_assert (0 ==
+                gcry_cipher_encrypt (queue->out_cipher,
+                                     &queue->cwrite_buf[queue->cwrite_off],
+                                     sizeof (tc),
+                                     &tc,
+                                     sizeof (tc)));
+  queue->cwrite_off += sizeof (tc);
+  
   return GNUNET_OK;
 }
 
@@ -895,6 +1337,11 @@ do_shutdown (void *cls)
                               GNUNET_NO);
     stats = NULL;
   }
+  if (NULL != my_private_key)
+  {
+    GNUNET_free (my_private_key);
+    my_private_key = NULL;
+  }
 }
 
 
@@ -903,7 +1350,7 @@ do_shutdown (void *cls)
  * acknowledgement for this communicator (!) via a different return
  * path.
  *
- * Not applicable for UNIX.
+ * Not applicable for TCP.
  *
  * @param cls closure
  * @param sender which peer sent the notification
@@ -927,13 +1374,13 @@ enc_notify_cb (void *cls,
  * @param cls NULL (always)
  * @param args remaining command-line arguments
  * @param cfgfile name of the configuration file used (for saving, can be 
NULL!)
- * @param cfg configuration
+ * @param c configuration
  */
 static void
 run (void *cls,
      char *const *args,
      const char *cfgfile,
-     const struct GNUNET_CONFIGURATION_Handle *cfg)
+     const struct GNUNET_CONFIGURATION_Handle *c)
 {
   char *bindto;
   struct sockaddr *in;
@@ -941,6 +1388,7 @@ run (void *cls,
   char *my_addr;
   (void) cls;
 
+  cfg = c;
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_filename (cfg,
                                               COMMUNICATOR_CONFIG_SECTION,
@@ -1002,6 +1450,17 @@ run (void *cls,
                                    cfg);
   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
                                 NULL);
+  my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
+  if (NULL == my_private_key)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                _("Transport service is lacking key configuration settings. 
Exiting.\n"));
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
+  GNUNET_CRYPTO_eddsa_key_get_public (my_private_key,
+                                      &my_identity.public_key);
+
   listen_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
                                               listen_sock,
                                               &listen_cb,
diff --git a/src/transport/gnunet-communicator-unix.c 
b/src/transport/gnunet-communicator-unix.c
index 08f02b66d..d30acbd5f 100644
--- a/src/transport/gnunet-communicator-unix.c
+++ b/src/transport/gnunet-communicator-unix.c
@@ -234,7 +234,7 @@ queue_destroy (struct Queue *queue)
                                                       &queue->target,
                                                       queue));
   GNUNET_STATISTICS_set (stats,
-                        "# UNIX queues active",
+                        "# queues active",
                         GNUNET_CONTAINER_multipeermap_size (queue_map),
                         GNUNET_NO);
   if (NULL != queue->timeout_task)

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

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