gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] r25275 - gnunet/src/consensus


From: gnunet
Subject: [GNUnet-SVN] r25275 - gnunet/src/consensus
Date: Wed, 5 Dec 2012 22:41:09 +0100

Author: dold
Date: 2012-12-05 22:41:09 +0100 (Wed, 05 Dec 2012)
New Revision: 25275

Added:
   gnunet/src/consensus/gnunet-consensus-start-peers.c
   gnunet/src/consensus/ibf.c
   gnunet/src/consensus/ibf.h
Modified:
   gnunet/src/consensus/Makefile.am
   gnunet/src/consensus/consensus.h
   gnunet/src/consensus/consensus_api.c
   gnunet/src/consensus/gnunet-consensus.c
   gnunet/src/consensus/gnunet-service-consensus.c
   gnunet/src/consensus/test_consensus.conf
Log:
consensus api, consensus service (local), peer driver and ibf sketch


Modified: gnunet/src/consensus/Makefile.am
===================================================================
--- gnunet/src/consensus/Makefile.am    2012-12-05 21:40:51 UTC (rev 25274)
+++ gnunet/src/consensus/Makefile.am    2012-12-05 21:41:09 UTC (rev 25275)
@@ -16,7 +16,8 @@
 endif
 
 bin_PROGRAMS = \
- gnunet-consensus 
+ gnunet-consensus \
+ gnunet-consensus-start-peers
 
 libexec_PROGRAMS = \
  gnunet-service-consensus
@@ -31,6 +32,14 @@
   $(top_builddir)/src/consensus/libgnunetconsensus.la \
   $(GN_LIBINTL)
 
+gnunet_consensus_start_peers_SOURCES = \
+ gnunet-consensus-start-peers.c
+gnunet_consensus_start_peers_LDADD = \
+  $(top_builddir)/src/util/libgnunetutil.la \
+  $(top_builddir)/src/testbed/libgnunettestbed.la \
+  $(top_builddir)/src/consensus/libgnunetconsensus.la \
+  $(GN_LIBINTL)
+
 gnunet_service_consensus_SOURCES = \
  gnunet-service-consensus.c
 gnunet_service_consensus_LDADD = \

Modified: gnunet/src/consensus/consensus.h
===================================================================
--- gnunet/src/consensus/consensus.h    2012-12-05 21:40:51 UTC (rev 25274)
+++ gnunet/src/consensus/consensus.h    2012-12-05 21:41:09 UTC (rev 25275)
@@ -90,6 +90,20 @@
   /* rest: element data */
 };
 
+struct GNUNET_CONSENSUS_AckMessage
+{
+  /**
+   * Type: GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_ACK
+   */
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * Do we want to keep and propagate the element?
+   */
+  uint8_t keep;
+
+};
+
 GNUNET_NETWORK_STRUCT_END
 
 #endif

Modified: gnunet/src/consensus/consensus_api.c
===================================================================
--- gnunet/src/consensus/consensus_api.c        2012-12-05 21:40:51 UTC (rev 
25274)
+++ gnunet/src/consensus/consensus_api.c        2012-12-05 21:41:09 UTC (rev 
25275)
@@ -24,6 +24,7 @@
  * @author Florian Dold
  */
 #include "platform.h"
+#include "gnunet_util_lib.h"
 #include "gnunet_protocols.h"
 #include "gnunet_client_lib.h"
 #include "gnunet_consensus_service.h"
@@ -32,6 +33,13 @@
 
 #define LOG(kind,...) GNUNET_log_from (kind, "consensus-api",__VA_ARGS__)
 
+struct ElementAck
+{
+  struct ElementAck *next;
+  struct ElementAck *prev;
+  int keep;
+  struct GNUNET_CONSENSUS_Element *element;
+};
 
 /**
  * Handle for the service.
@@ -113,20 +121,138 @@
    * Deadline for the conclude operation.
    */
   struct GNUNET_TIME_Absolute conclude_deadline;
+
+  struct ElementAck *ack_head;
+  struct ElementAck *ack_tail;
+
+  /**
+   * Set to GNUNET_YES if the begin message has been transmitted to the service
+   */
+  int begin_sent;
+
+  /**
+   * Set to GNUNET_YES it the begin message should be transmitted to the 
service
+   */
+  int begin_requested;
 };
 
 
+static size_t
+transmit_ack (void *cls, size_t size, void *buf);
+
+static size_t
+transmit_insert (void *cls, size_t size, void *buf);
+
+static size_t
+transmit_conclude (void *cls, size_t size, void *buf);
+
+static size_t
+transmit_begin (void *cls, size_t size, void *buf);
+
+
+/**
+ * Call notify_transmit_ready for ack if necessary and possible.
+ */
 static void
+ntr_ack (struct GNUNET_CONSENSUS_Handle *consensus)
+{
+  if ((NULL == consensus->th) && (NULL != consensus->ack_head))
+  {
+    consensus->th =
+        GNUNET_CLIENT_notify_transmit_ready (consensus->client,
+                                             sizeof (struct 
GNUNET_CONSENSUS_AckMessage),
+                                             GNUNET_TIME_UNIT_FOREVER_REL,
+                                             GNUNET_NO, &transmit_ack, 
consensus);
+  }
+}
+
+
+/**
+ * Call notify_transmit_ready for ack if necessary and possible.
+ */
+static void
+ntr_insert (struct GNUNET_CONSENSUS_Handle *consensus)
+{
+  if ((NULL == consensus->th) && (NULL != consensus->insert_element))
+  {
+    consensus->th =
+        GNUNET_CLIENT_notify_transmit_ready (consensus->client,
+                                             sizeof (struct 
GNUNET_CONSENSUS_ElementMessage) + 
+                                                
consensus->insert_element->size,
+                                             GNUNET_TIME_UNIT_FOREVER_REL,
+                                             GNUNET_NO, &transmit_insert, 
consensus);
+  }
+}
+
+
+/**
+ * Call notify_transmit_ready for ack if necessary and possible.
+ */
+static void
+ntr_conclude (struct GNUNET_CONSENSUS_Handle *consensus)
+{
+  if ((NULL == consensus->th) && (NULL != consensus->conclude_cb))
+  {
+    consensus->th =
+        GNUNET_CLIENT_notify_transmit_ready (consensus->client,
+                                             sizeof (struct 
GNUNET_CONSENSUS_ConcludeMessage),
+                                             
GNUNET_TIME_absolute_get_remaining (consensus->conclude_deadline),
+                                             GNUNET_NO, &transmit_conclude, 
consensus);
+  }
+}
+
+
+/**
+ * Call notify_transmit_ready for ack if necessary and possible.
+ */
+static void
+ntr_begin (struct GNUNET_CONSENSUS_Handle *consensus)
+{
+  if ((NULL == consensus->th) && (GNUNET_YES == consensus->begin_requested) &&
+      (GNUNET_NO == consensus->begin_sent))
+  {
+    consensus->th =
+        GNUNET_CLIENT_notify_transmit_ready (consensus->client,
+                                             sizeof (struct 
GNUNET_MessageHeader),
+                                             GNUNET_TIME_UNIT_FOREVER_REL,
+                                             GNUNET_NO, &transmit_begin, 
consensus);
+  }
+}
+
+/**
+ * Called when the server has sent is a new element
+ * 
+ * @param consensus consensus handle
+ * @param msg element message
+ */
+static void
 handle_new_element(struct GNUNET_CONSENSUS_Handle *consensus,
                    struct GNUNET_CONSENSUS_ElementMessage *msg)
 {
   struct GNUNET_CONSENSUS_Element element;
+  struct ElementAck *ack;
+  int ret;
+
   element.type = msg->element_type;
   element.size = msg->header.size - sizeof (struct 
GNUNET_CONSENSUS_ElementMessage);
   element.data = &msg[1];
-  consensus->new_element_cb (consensus->new_element_cls, &element);
+
+  ret = consensus->new_element_cb (consensus->new_element_cls, &element);
+  ack = GNUNET_malloc (sizeof (struct ElementAck));
+  ack->keep = ret;
+  GNUNET_CONTAINER_DLL_insert_tail (consensus->ack_head, 
consensus->ack_tail,ack);
+
+  ntr_ack (consensus);
 }
 
+
+/**
+ * Called when the server has announced
+ * that the conclusion is over.
+ * 
+ * @param consensus consensus handle
+ * @param msg conclude done message
+ */
 static void
 handle_conclude_done(struct GNUNET_CONSENSUS_Handle *consensus,
                      struct GNUNET_CONSENSUS_ConcludeDoneMessage *msg)
@@ -170,7 +296,7 @@
     return;
   }
 
-  switch (ntohs(msg->type))
+  switch (ntohs (msg->type))
   {
     case GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_RECEIVED_ELEMENT:
       handle_new_element (consensus, (struct GNUNET_CONSENSUS_ElementMessage 
*) msg);
@@ -200,6 +326,43 @@
  * @return number of bytes written to buf
  */
 static size_t
+transmit_ack (void *cls, size_t size, void *buf)
+{
+  struct GNUNET_CONSENSUS_AckMessage *msg;
+  struct GNUNET_CONSENSUS_Handle *consensus;
+
+  consensus = (struct GNUNET_CONSENSUS_Handle *) cls;
+
+  GNUNET_assert (NULL != consensus->ack_head);
+
+  msg = (struct GNUNET_CONSENSUS_AckMessage *) buf;
+  msg->keep = consensus->ack_head->keep;
+  msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_ACK);
+  msg->header.size = htons (sizeof (struct GNUNET_CONSENSUS_AckMessage));
+
+  consensus->ack_head = consensus->ack_head->next;
+
+  consensus->th = NULL;
+
+  ntr_insert (consensus);
+  ntr_ack (consensus);
+  ntr_conclude (consensus);
+
+  return sizeof (struct GNUNET_CONSENSUS_AckMessage);
+}
+
+/**
+ * Function called to notify a client about the connection
+ * begin ready to queue more data.  "buf" will be
+ * NULL and "size" zero if the connection was closed for
+ * writing in the meantime.
+ *
+ * @param cls closure
+ * @param size number of bytes available in buf
+ * @param buf where the callee should write the message
+ * @return number of bytes written to buf
+ */
+static size_t
 transmit_insert (void *cls, size_t size, void *buf)
 {
   struct GNUNET_CONSENSUS_ElementMessage *msg;
@@ -227,6 +390,7 @@
           consensus->insert_element->data,
           consensus->insert_element->size);
 
+  consensus->insert_element = NULL;
 
   idc = consensus->idc;
   consensus->idc = NULL;
@@ -234,6 +398,11 @@
   consensus->idc_cls = NULL;
   idc (idc_cls, GNUNET_YES);
 
+
+  ntr_ack (consensus);
+  ntr_insert (consensus);
+  ntr_conclude (consensus);
+
   return msize;
 }
 
@@ -273,18 +442,14 @@
   msg->header.size = htons (msize);
   msg->session_id = consensus->session_id;
   msg->num_peers = htons (consensus->num_peers);
-  memcpy(&msg[1],
-         consensus->peers,
-         consensus->num_peers * sizeof (struct GNUNET_PeerIdentity));
+  if (0 != msg->num_peers)
+    memcpy(&msg[1],
+           consensus->peers,
+           consensus->num_peers * sizeof (struct GNUNET_PeerIdentity));
 
-  if (consensus->insert_element != NULL)
-  {
-    consensus->th =
-        GNUNET_CLIENT_notify_transmit_ready (consensus->client,
-                                             msize,
-                                             GNUNET_TIME_UNIT_FOREVER_REL,
-                                             GNUNET_NO, &transmit_insert, 
consensus);
-  }
+  ntr_insert (consensus);
+  ntr_begin (consensus);
+  ntr_conclude (consensus);
 
   GNUNET_CLIENT_receive (consensus->client, &message_handler, consensus,
                          GNUNET_TIME_UNIT_FOREVER_REL);
@@ -325,6 +490,8 @@
   msg->timeout =
       GNUNET_TIME_relative_hton 
(GNUNET_TIME_absolute_get_remaining(consensus->conclude_deadline));
 
+  ntr_ack (consensus);
+
   return msize;
 }
 
@@ -359,6 +526,10 @@
   msg->type = htons (GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_BEGIN);
   msg->size = htons (msize);
 
+  ntr_ack (consensus);
+  ntr_insert (consensus);
+  ntr_conclude (consensus);
+
   return msize;
 }
 
@@ -421,8 +592,8 @@
                                            GNUNET_TIME_UNIT_FOREVER_REL,
                                            GNUNET_NO, &transmit_join, 
consensus);
 
+
   GNUNET_assert (consensus->th != NULL);
-
   return consensus;
 }
 
@@ -444,9 +615,9 @@
                         GNUNET_CONSENSUS_InsertDoneCallback idc,
                         void *idc_cls)
 {
-
   GNUNET_assert (NULL == consensus->idc);
   GNUNET_assert (NULL == consensus->insert_element);
+  GNUNET_assert (NULL == consensus->conclude_cb);
 
   consensus->idc = idc;
   consensus->idc_cls = idc_cls;
@@ -454,17 +625,10 @@
 
   if (consensus->joined == 0)
   {
-    GNUNET_assert (NULL != consensus->th);
     return;
   }
 
-  GNUNET_assert (NULL == consensus->th);
-
-  consensus->th =
-      GNUNET_CLIENT_notify_transmit_ready (consensus->client,
-                                           element->size + sizeof (struct 
GNUNET_CONSENSUS_ElementMessage),
-                                           GNUNET_TIME_UNIT_FOREVER_REL,
-                                           GNUNET_NO, &transmit_insert, 
consensus);
+  ntr_insert (consensus);
 }
 
 
@@ -478,12 +642,12 @@
 {
   GNUNET_assert (NULL == consensus->idc);
   GNUNET_assert (NULL == consensus->insert_element);
+  GNUNET_assert (GNUNET_NO == consensus->begin_requested);
+  GNUNET_assert (GNUNET_NO == consensus->begin_sent);
 
-  consensus->th =
-      GNUNET_CLIENT_notify_transmit_ready (consensus->client,
-                                           sizeof (struct 
GNUNET_MessageHeader),
-                                           GNUNET_TIME_UNIT_FOREVER_REL,
-                                           GNUNET_NO, &transmit_begin, 
consensus);
+  consensus->begin_requested = GNUNET_YES;
+
+  ntr_begin (consensus);
 }
 
 
@@ -503,22 +667,17 @@
                           GNUNET_CONSENSUS_ConcludeCallback conclude,
                           void *conclude_cls)
 {
-  GNUNET_assert (NULL == consensus->th);
+  GNUNET_assert (NULL != conclude);
   GNUNET_assert (NULL == consensus->conclude_cb);
 
   consensus->conclude_cls = conclude_cls;
   consensus->conclude_cb = conclude;
   consensus->conclude_deadline = GNUNET_TIME_relative_to_absolute(timeout);
 
-  consensus->th =
-      GNUNET_CLIENT_notify_transmit_ready (consensus->client,
-                                           sizeof (struct 
GNUNET_CONSENSUS_ConcludeMessage),
-                                           timeout,
-                                           GNUNET_NO, &transmit_conclude, 
consensus);
-  if (NULL == consensus->th)
-  {
-    conclude(conclude_cls, 0, NULL);
-  }
+
+  /* if transmitting the conclude message is not possible right now, 
transmit_join
+   * or transmit_ack will handle it */
+  ntr_conclude (consensus);
 }
 
 
@@ -536,7 +695,8 @@
     GNUNET_CLIENT_disconnect (consensus->client);
     consensus->client = NULL;
   }
-  GNUNET_free (consensus->peers);
+  if (NULL != consensus->peers)
+    GNUNET_free (consensus->peers);
   GNUNET_free (consensus);
 }
 

Added: gnunet/src/consensus/gnunet-consensus-start-peers.c
===================================================================
--- gnunet/src/consensus/gnunet-consensus-start-peers.c                         
(rev 0)
+++ gnunet/src/consensus/gnunet-consensus-start-peers.c 2012-12-05 21:41:09 UTC 
(rev 25275)
@@ -0,0 +1,172 @@
+
+/*
+      This file is part of GNUnet
+      (C) 2012 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 2, 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 consensus/gnunet-consensus-start-peers.c
+ * @brief Starts peers with testebed on localhost,
+ *        prints their configuration files and waits for ^C.
+ * @author Florian Dold
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_testbed_service.h"
+
+
+static char *config_template_file;
+static unsigned int num_peers_requested = 2;
+static struct GNUNET_TESTBED_Peer **peers;
+
+
+/**
+ * Callback to be called when the requested peer information is available
+ *
+ * @param cb_cls the closure from GNUNET_TETSBED_peer_get_information()
+ * @param op the operation this callback corresponds to
+ * @param pinfo the result; will be NULL if the operation has failed
+ * @param emsg error message if the operation has failed; will be NULL if the
+ *          operation is successfull
+ */
+static void
+peer_info_cb (void *cb_cls,
+              struct GNUNET_TESTBED_Operation
+              *op,
+              const struct
+              GNUNET_TESTBED_PeerInformation
+              *pinfo,
+              const char *emsg)
+{
+  GNUNET_assert (NULL == emsg);
+  if (pinfo->pit == GNUNET_TESTBED_PIT_IDENTITY)
+  {
+    struct GNUNET_CRYPTO_HashAsciiEncoded enc;
+    GNUNET_CRYPTO_hash_to_enc (&pinfo->result.id->hashPubKey, &enc);
+    printf("peer %td identity:\n", ((struct GNUNET_TESTBED_Peer **) cb_cls) - 
&peers[0]);
+    printf("%s\n", (char *)&enc);
+  }
+  else if (pinfo->pit == GNUNET_TESTBED_PIT_CONFIGURATION)
+  {
+    char *tmpfilename;
+    if (NULL == (tmpfilename = GNUNET_DISK_mktemp ("gnunet-consensus")))
+    {
+      GNUNET_break (0);
+      GNUNET_SCHEDULER_shutdown ();
+      return;
+    }
+    if (GNUNET_SYSERR == 
+        GNUNET_CONFIGURATION_write (pinfo->result.cfg,
+                                    tmpfilename))
+    {
+      GNUNET_break (0);
+      return;
+    }
+    printf("peer %td config file:\n", ((struct GNUNET_TESTBED_Peer **) cb_cls) 
- &peers[0]);
+    printf("%s\n", tmpfilename);
+  }
+  else
+  {
+    GNUNET_assert (0);
+  }
+}
+
+
+
+/**
+ * Signature of the event handler function called by the
+ * respective event controller.
+ *
+ * @param cls closure
+ * @param event information about the event
+ */
+static void
+controller_cb(void *cls,
+              const struct GNUNET_TESTBED_EventInformation *event)
+{
+  GNUNET_assert (0);
+}
+
+
+
+
+static void
+test_master (void *cls,
+             unsigned int num_peers,
+             struct GNUNET_TESTBED_Peer **started_peers)
+{
+  int i;
+
+  printf("started %d peers\n", num_peers);
+  peers = started_peers;
+
+  for (i = 0; i < num_peers; i++)
+  {
+    GNUNET_TESTBED_peer_get_information (peers[i],
+                                         GNUNET_TESTBED_PIT_IDENTITY,
+                                         peer_info_cb,
+                                         &peers[i]);
+    GNUNET_TESTBED_peer_get_information (peers[i],
+                                         GNUNET_TESTBED_PIT_CONFIGURATION,
+                                         peer_info_cb,
+                                         &peers[i]);
+  }
+}
+
+
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+     const struct GNUNET_CONFIGURATION_Handle *config)
+{
+  if (NULL == config_template_file)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "no template file specified\n");
+    return;
+  }
+
+  GNUNET_TESTBED_test_run ("gnunet-consensus-start-peers",
+                           config_template_file,
+                           num_peers_requested,
+                           0,
+                           controller_cb,
+                           NULL,
+                           test_master,
+                           NULL);
+}
+
+
+int
+main (int argc, char **argv)
+{
+  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+      { 't', "config-template", "TEMPLATE",
+        gettext_noop ("start peers with the given template configuration"),
+        GNUNET_YES, &GNUNET_GETOPT_set_string, &config_template_file },
+      { 'n', "num-peers", "NUM",
+        gettext_noop ("number of peers to start"),
+        GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_peers_requested },
+      GNUNET_GETOPT_OPTION_END
+   };
+
+  /* run without scheduler, as test_run already does this */
+  GNUNET_PROGRAM_run2 (argc, argv, "gnunet-consensus-start-peers",
+                     "help",
+                     options, &run, NULL, GNUNET_YES);
+  return 0;
+}
+

Modified: gnunet/src/consensus/gnunet-consensus.c
===================================================================
--- gnunet/src/consensus/gnunet-consensus.c     2012-12-05 21:40:51 UTC (rev 
25274)
+++ gnunet/src/consensus/gnunet-consensus.c     2012-12-05 21:41:09 UTC (rev 
25275)
@@ -29,8 +29,114 @@
 
 
 
+/**
+ * Handle to the consensus service
+ */
+static struct GNUNET_CONSENSUS_Handle *consensus;
+/**
+ * Session id
+ */
+static char *session_id_str;
 
 /**
+ * File handle to STDIN
+ */
+static struct GNUNET_DISK_FileHandle *stdin_fh;
+
+/**
+ * Task for reading from stdin
+ */
+static GNUNET_SCHEDULER_TaskIdentifier stdin_tid = GNUNET_SCHEDULER_NO_TASK;
+
+/**
+ * Element currently being sent to the service
+ */
+static struct GNUNET_CONSENSUS_Element *element;
+
+
+
+static void
+stdin_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Called when a conclusion was successful.
+ *
+ * @param cls
+ * @param num_peers_in_consensus
+ * @param peers_in_consensus
+ */
+static void
+conclude_cb (void *cls, 
+             unsigned int num_peers_in_consensus,
+             const struct GNUNET_PeerIdentity *peers_in_consensus)
+{
+  printf("reached conclusion with %d peers\n", num_peers_in_consensus);
+  GNUNET_SCHEDULER_shutdown ();
+}
+
+
+
+static void
+insert_done_cb (void *cls,
+                int success)
+{
+  if (GNUNET_YES != success)
+  {
+    printf ("insert failed\n");
+    GNUNET_SCHEDULER_shutdown ();
+  }
+
+  GNUNET_free (element);
+
+  GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == stdin_tid);
+
+  stdin_tid = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, 
stdin_fh,
+                                        &stdin_cb, NULL);    
+}
+
+
+/**
+ * Called whenever we can read stdin non-blocking 
+ *
+ * @param cls unused
+ * @param tc scheduler context 
+ */
+static void
+stdin_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  char buf[1024];
+  char *ret;
+  ret = fgets (buf, 1024, stdin);
+
+  stdin_tid = GNUNET_SCHEDULER_NO_TASK;
+
+  if (NULL == ret)
+  {
+    if (feof (stdin))
+    {
+      printf ("concluding ...\n");
+      GNUNET_CONSENSUS_conclude (consensus, GNUNET_TIME_UNIT_FOREVER_REL, 
conclude_cb, NULL);
+    }
+    else
+    {
+      GNUNET_SCHEDULER_shutdown ();
+    }
+    return;
+  }
+
+  printf("read: %s", buf);
+
+  element = GNUNET_malloc (sizeof (struct GNUNET_CONSENSUS_Element) + 
strlen(buf) + 1);
+  element->type = 0;
+  element->size = strlen(buf) + 1;
+  element->data = &element[1];
+  strcpy((char *) &element[1], buf);
+
+  GNUNET_CONSENSUS_insert (consensus, element, insert_done_cb, NULL);
+}
+
+/**
  * Called when a new element was received from another peer, or an error 
occured.
  *
  * May deliver duplicate values.
@@ -47,23 +153,82 @@
 cb (void *cls,
     struct GNUNET_CONSENSUS_Element *element)
 {
-  return 0;
+  printf("got element\n");
+  return GNUNET_YES;
 }
 
+/**
+ * Function run on shutdown to clean up.
+ *
+ * @param cls the statistics handle
+ * @param tc scheduler context
+ */
+static void
+shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
 
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "shutting down\n");
+  if (NULL == consensus)
+  {
+    return;
+  }
 
+  GNUNET_CONSENSUS_destroy (consensus);
+}
+
+
 static void
 run (void *cls, char *const *args, const char *cfgfile,
      const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
-  static struct GNUNET_PeerIdentity pid;
-  static struct GNUNET_HashCode sid;
+  struct GNUNET_HashCode sid;
+  struct GNUNET_PeerIdentity *pids;
+  int count;
+  int i;
+
+  if (NULL == session_id_str)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "no session id given\n");
+    return;
+  }
+
+  for (count = 0; NULL != args[count]; count++);
+ 
+  if (0 != count)
+  { 
+    pids = GNUNET_malloc (count * sizeof (struct GNUNET_PeerIdentity));
+  }
+  else
+  {
+    pids = NULL;
+  }
+
+  for (i = 0; i < count; i++)
+  {
+    int ret;
+    ret = GNUNET_CRYPTO_hash_from_string (args[i], &pids[i].hashPubKey);
+    if (GNUNET_OK != ret)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "peer identity '%s' is 
malformed\n", args[i]);
+      return;
+    }
+  }
+
+  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
+                                &shutdown_task, NULL);
   
-  GNUNET_CONSENSUS_create (cfg,
-                          1, &pid,
-                          &sid,
-                          &cb, NULL);
-  
+  consensus = 
+      GNUNET_CONSENSUS_create (cfg,
+                               count, pids,
+                               &sid,
+                               &cb, NULL);
+
+  GNUNET_CONSENSUS_begin (consensus);
+
+
+  stdin_fh = GNUNET_DISK_get_handle_from_native (stdin);
+  stdin_tid = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, 
stdin_fh,
+                                        &stdin_cb, NULL);
 }
 
 
@@ -71,6 +236,9 @@
 main (int argc, char **argv)
 {
    static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+      { 's', "session-id", "ID",
+        gettext_noop ("session identifier"),
+        GNUNET_YES, &GNUNET_GETOPT_set_string, &session_id_str },
         GNUNET_GETOPT_OPTION_END
    };
   GNUNET_PROGRAM_run (argc, argv, "gnunet-consensus",

Modified: gnunet/src/consensus/gnunet-service-consensus.c
===================================================================
--- gnunet/src/consensus/gnunet-service-consensus.c     2012-12-05 21:40:51 UTC 
(rev 25274)
+++ gnunet/src/consensus/gnunet-service-consensus.c     2012-12-05 21:41:09 UTC 
(rev 25275)
@@ -20,19 +20,19 @@
 
 
 #include "platform.h"
+#include "gnunet_common.h"
 #include "gnunet_protocols.h"
-#include "gnunet_common.h"
-#include "gnunet_service_lib.h"
+#include "gnunet_util_lib.h"
 #include "gnunet_consensus_service.h"
 #include "gnunet_core_service.h"
-#include "gnunet_container_lib.h"
+#include "gnunet_mesh_service.h"
 #include "consensus.h"
 
 
-struct ConsensusClient;
+struct ConsensusSession;
 
 static void
-send_next (struct ConsensusClient *cli);
+send_next (struct ConsensusSession *session);
 
 
 /**
@@ -58,8 +58,7 @@
 
 
 /**
- * A consensus session consists of one or more local clients,
- * as well as zero or more remote authorities.
+ * A consensus session consists of one local client and the remote authorities.
  */
 struct ConsensusSession
 {
@@ -74,18 +73,8 @@
   struct ConsensusSession *prev;
 
   /**
-   * Consensus clients are kept in a DLL.
+   * Local consensus identification, chosen by clients.
    */
-  struct ConsensusClient *clients_head;
-
-  /**
-   * Consensus clients are kept in a DLL.
-   */
-  struct ConsensusClient *clients_tail;
-
-  /**
-  * Local consensus identification, chosen by clients.
-  */
   struct GNUNET_HashCode *local_id;
  
   /**
@@ -95,24 +84,6 @@
   struct GNUNET_HashCode *global_id;
 
   /**
-   * Values in the consensus set of this session.
-   */
-  struct GNUNET_CONTAINER_MultiHashMap *values;
-};
-
-
-struct ConsensusClient
-{
-  /**
-   * Consensus clients are kept in a DLL.
-   */
-  struct ConsensusClient *next;
-  /**
-   * Consensus clients are kept in a DLL.
-   */
-  struct ConsensusClient *prev;
-
-  /**
    * Corresponding server handle.
    */
   struct GNUNET_SERVER_Client *client;
@@ -123,26 +94,32 @@
   int begin;
 
   /**
-   * Session this client belongs to
+   * Values in the consensus set of this session,
+   * all of them either have been sent or approved by the client.
    */
-  struct ConsensusSession *session;
+  struct GNUNET_CONTAINER_MultiHashMap *values;
 
   /**
-   * Values in the consensus set of this client.
-   * Includes pending elements.
+   * Elements that have not been sent to the client yet.
    */
-  struct GNUNET_CONTAINER_MultiHashMap *values;
+  struct PendingElement *transmit_pending_head;
 
   /**
-   * Elements that have not been set to the client yet.
+   * Elements that have not been sent to the client yet.
    */
-  struct PendingElement *pending_head;
+  struct PendingElement *transmit_pending_tail;
+
   /**
-   * Elements that have not been set to the client yet.
+   * Elements that have not been sent to the client yet.
    */
-  struct PendingElement *pending_tail;
+  struct PendingElement *approval_pending_head;
 
   /**
+   * Elements that have not been sent to the client yet.
+   */
+  struct PendingElement *approval_pending_tail;
+
+  /**
    * Currently active transmit handle for sending to the client
    */
   struct GNUNET_SERVER_TransmitHandle *th;
@@ -157,6 +134,11 @@
    * Client has been informed about the conclusion.
    */
   int conclude_sent;
+
+  /**
+   * Number of other peers in the consensus
+   */
+  int num_peers;
 };
 
 
@@ -185,30 +167,6 @@
  */
 static struct GNUNET_PeerIdentity *my_peer;
 
-
-struct ConsensusClient *
-find_client (const struct GNUNET_SERVER_Client *srv_client)
-{
-  struct ConsensusSession *session;
-  struct ConsensusClient *client;
-
-  session = sessions_head;
-  while (NULL != session)
-  {
-    client = session->clients_head;
-    while (NULL != client)
-    {
-      if (client->client == srv_client)
-      {
-        return client;
-      }
-      client = client->next;
-    }
-    session = session->next;
-  }
-  return NULL;
-}
-
 static void
 disconnect_client (struct GNUNET_SERVER_Client *client)
 {
@@ -221,74 +179,45 @@
                    const struct GNUNET_PeerIdentity *peers,
                    int num_peers)
 {
+  int i;
+  struct GNUNET_HashCode tmp;
+
   *dst = *local_id;
-
-  /* FIXME: hash other peers into global id */
-}
-
-
-
-/**
- * Iterator over hash map entries.
- *
- * @param cls closure, the client
- * @param key current key code
- * @param value value in the hash map
- * @return GNUNET_YES if we should continue to
- *         iterate,
- *         GNUNET_NO if not.
- */
-int
-update_pending (void *cls,
-                 const struct GNUNET_HashCode *key,
-                 void *value)
-{
-  struct ConsensusClient *cli;
-  struct GNUNET_CONSENSUS_Element *element;
-  struct PendingElement *pending_element;
-
-  cli = (struct ConsensusClient *) cls;
-  element = (struct GNUNET_CONSENSUS_Element *) value;
-  pending_element = GNUNET_malloc (sizeof (struct PendingElement));
-  pending_element->element = element;
-
-  if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (cli->values, key))
+  for (i = 0; i < num_peers; ++i)
   {
-    GNUNET_CONTAINER_DLL_insert_tail (cli->pending_head, cli->pending_tail, 
pending_element);
-    GNUNET_CONTAINER_multihashmap_put (cli->values, key, element, 
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
+    /* FIXME: maybe hash_xor/hash allow aliased source/target, and we can get 
by without tmp */
+    GNUNET_CRYPTO_hash_xor (dst, &peers[0].hashPubKey, &tmp);
+    *dst = tmp;
+    GNUNET_CRYPTO_hash (dst, sizeof (struct GNUNET_PeerIdentity), &tmp);
+    *dst = tmp;
   }
-  
-  return GNUNET_YES;
 }
 
 
-
-
 static size_t
 transmit_pending (void *cls, size_t size, void *buf)
 {
   struct GNUNET_CONSENSUS_Element *element;
   struct GNUNET_CONSENSUS_ElementMessage *msg;
-  struct ConsensusClient *cli;
+  struct ConsensusSession *session;
 
-  cli = (struct ConsensusClient *) cls;
+  session = (struct ConsensusSession *) cls;
   msg = (struct GNUNET_CONSENSUS_ElementMessage *) buf;
-  element = cli->pending_head->element;
+  element = session->transmit_pending_head->element;
 
   GNUNET_assert (NULL != element);
 
-  cli->th = NULL;
+  session->th = NULL;
 
   msg->element_type = element->type;
   msg->header.type = htons 
(GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_RECEIVED_ELEMENT);
   msg->header.size = htons (sizeof (struct GNUNET_CONSENSUS_ElementMessage) + 
element->size);
   memcpy (&msg[1], element->data, element->size);
 
+  session->transmit_pending_head = session->transmit_pending_head->next;
 
-  cli->pending_head = cli->pending_head->next;
+  send_next (session);
 
-  send_next (cli);
-
   return sizeof (struct GNUNET_CONSENSUS_ElementMessage) + element->size;
 }
 
@@ -299,7 +228,7 @@
   struct GNUNET_CONSENSUS_ConcludeDoneMessage *msg;
 
   msg = (struct GNUNET_CONSENSUS_ConcludeDoneMessage *) buf;
-  msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_CONCLUDE);
+  msg->header.type = htons 
(GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_CONCLUDE_DONE);
   msg->header.size = htons (sizeof (struct 
GNUNET_CONSENSUS_ConcludeDoneMessage));
   msg->num_peers = htons (0);
 
@@ -313,38 +242,43 @@
  * @param cli the client to send the next message to
  */
 static void
-send_next (struct ConsensusClient *cli)
+send_next (struct ConsensusSession *session)
 {
   int msize;
 
-  GNUNET_assert (NULL != cli);
+  GNUNET_assert (NULL != session);
 
-  if (NULL != cli->th)
+  if (NULL != session->th)
   {
     return;
   }
 
-  if ((cli->conclude_requested == GNUNET_YES) && (cli->conclude_sent == 
GNUNET_NO))
+  if ((session->conclude_requested == GNUNET_YES) && (session->conclude_sent 
== GNUNET_NO))
   {
     /* just the conclude message with no other authorities in the dummy */
     msize = sizeof (struct GNUNET_CONSENSUS_ConcludeMessage);
-    cli->th =
-        GNUNET_SERVER_notify_transmit_ready (cli->client, msize,
-                                             GNUNET_TIME_UNIT_FOREVER_REL, 
&transmit_conclude_done, cli);
-    cli->conclude_sent = GNUNET_YES;
+    session->th =
+        GNUNET_SERVER_notify_transmit_ready (session->client, msize,
+                                             GNUNET_TIME_UNIT_FOREVER_REL, 
&transmit_conclude_done, session);
+    session->conclude_sent = GNUNET_YES;
   }
-  else if (NULL != cli->pending_head)
+  else if (NULL != session->transmit_pending_head)
   {
-    msize = cli->pending_head->element->size + sizeof (struct 
GNUNET_CONSENSUS_ElementMessage);
-    cli->th =
-        GNUNET_SERVER_notify_transmit_ready (cli->client, msize,
-                                             GNUNET_TIME_UNIT_FOREVER_REL, 
&transmit_pending, cli);
+    msize = session->transmit_pending_head->element->size + sizeof (struct 
GNUNET_CONSENSUS_ElementMessage);
+    session->th =
+        GNUNET_SERVER_notify_transmit_ready (session->client, msize,
+                                             GNUNET_TIME_UNIT_FOREVER_REL, 
&transmit_pending, session);
+    /* TODO: insert into ack pending */
   }
 }
 
 
 /**
  * Called when a client wants to join a consensus session.
+ *
+ * @param cls unused
+ * @param client client that sent the message
+ * @param m message sent by the client
  */
 static void
 client_join (void *cls,
@@ -354,58 +288,42 @@
   struct GNUNET_HashCode global_id;
   const struct GNUNET_CONSENSUS_JoinMessage *msg;
   struct ConsensusSession *session;
-  struct ConsensusClient *consensus_client;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "join\n");
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "client joining\n");
 
-  fprintf(stderr, "foobar\n");
-
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "client joined\n");
-
   msg = (struct GNUNET_CONSENSUS_JoinMessage *) m;
-  
-  /* kill the client if it already is in a session */
-  if (NULL != find_client (client))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "client tried to join twice\n");
-    disconnect_client (client);
-    return;
-  }
 
-  consensus_client = GNUNET_malloc (sizeof (struct ConsensusClient));
-  consensus_client->client = client;
-  consensus_client->begin = GNUNET_NO;
-  consensus_client->values = GNUNET_CONTAINER_multihashmap_create (4, 
GNUNET_NO);
-
-  GNUNET_SERVER_client_keep (client);
-
-  GNUNET_assert (NULL != consensus_client->values);
-
   compute_global_id (&global_id, &msg->session_id, (struct GNUNET_PeerIdentity 
*) &m[1], msg->num_peers);
 
-  /* look if we already have a session for this local id */
   session = sessions_head;
   while (NULL != session)
   {
-    if (0 == memcmp(&global_id, session->global_id, sizeof (struct 
GNUNET_HashCode)))
+    if (client == session->client)
     {
-      GNUNET_CONTAINER_DLL_insert (session->clients_head, 
session->clients_tail, consensus_client);
-      GNUNET_SERVER_receive_done (client, GNUNET_OK);
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "client already in session\n");
+      disconnect_client (client);
       return;
     }
-    session = session->next;
+    if (0 == memcmp (session->global_id, &global_id, sizeof (struct 
GNUNET_HashCode)))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "session already owned by another 
client\n");
+      disconnect_client (client);
+      return;
+    }
   }
 
+  GNUNET_SERVER_client_keep (client);
+
   /* session does not exist yet, create it */
   session = GNUNET_malloc (sizeof (struct ConsensusSession));
   session->local_id = GNUNET_memdup (&msg->session_id, sizeof (struct 
GNUNET_HashCode));
   session->global_id = GNUNET_memdup (&global_id, sizeof (struct 
GNUNET_HashCode));
   session->values = GNUNET_CONTAINER_multihashmap_create (4, GNUNET_NO);
+  session->client = client;
 
   GNUNET_CONTAINER_DLL_insert (sessions_head, sessions_tail, session);
-  GNUNET_CONTAINER_DLL_insert (session->clients_head, session->clients_tail, 
consensus_client);
 
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "created new session");
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "created new session\n");
 
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
@@ -419,18 +337,22 @@
              struct GNUNET_SERVER_Client *client,
              const struct GNUNET_MessageHeader *m)
 {
-  struct ConsensusClient *consensus_client;
+  struct ConsensusSession *session;
   struct GNUNET_CONSENSUS_ElementMessage *msg;
   struct GNUNET_CONSENSUS_Element *element;
-  struct PendingElement *pending_element;
   struct GNUNET_HashCode key;
   int element_size;
 
   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "insert\n");
 
-  consensus_client = find_client (client);
+  session = sessions_head;
+  while (NULL != session)
+  {
+    if (session->client == client)
+      break;
+  }
 
-  if (NULL == consensus_client)
+  if (NULL == session)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "client tried to insert, but client 
is not in any session\n");
     GNUNET_SERVER_client_disconnect (client);
@@ -449,28 +371,12 @@
 
   GNUNET_CRYPTO_hash (element, element_size, &key);
 
-  GNUNET_CONTAINER_multihashmap_put (consensus_client->session->values, &key, 
element,
+  GNUNET_CONTAINER_multihashmap_put (session->values, &key, element,
                                      
GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
-  GNUNET_CONTAINER_multihashmap_put (consensus_client->values, &key, element,
-                                     
GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
 
-  /* send the new value to all clients that don't have it */
+  GNUNET_SERVER_receive_done (client, GNUNET_OK);
 
-  consensus_client = consensus_client->session->clients_head;
-  while (NULL != consensus_client)
-  {
-    if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains 
(consensus_client->values, &key))
-    {
-      pending_element = GNUNET_malloc (sizeof (struct PendingElement));
-      pending_element->element = element;
-      GNUNET_CONTAINER_DLL_insert_tail (consensus_client->pending_head, 
consensus_client->pending_tail, pending_element);
-      GNUNET_CONTAINER_multihashmap_put (consensus_client->values, &key, 
element,
-                                         
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
-      send_next (consensus_client);
-    }
-  }
-
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
+  send_next (session);
 }
 
 
@@ -482,20 +388,27 @@
              struct GNUNET_SERVER_Client *client,
              const struct GNUNET_MessageHeader *message)
 {
-  struct ConsensusClient *consensus_client;
+  struct ConsensusSession *session;
 
-  consensus_client = find_client (client);
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "client requested begin\n");
 
-  if (NULL == consensus_client)
+  session = sessions_head;
+  while (NULL != session)
   {
+    if (session->client == client)
+      break;
+  }
+
+  if (NULL == session)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "client tried to 'begin', but 
client is not in any session\n");
     GNUNET_SERVER_client_disconnect (client);
     return;
   }
 
-  consensus_client->begin = GNUNET_YES;
+  session->begin = GNUNET_YES;
 
-  GNUNET_CONTAINER_multihashmap_iterate (consensus_client->session->values, 
&update_pending, NULL);
-  send_next (consensus_client);
+  send_next (session);
 
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
@@ -510,21 +423,36 @@
              struct GNUNET_SERVER_Client *client,
              const struct GNUNET_MessageHeader *message)
 {
-  struct ConsensusClient *consensus_client;
+  struct ConsensusSession *session;
 
-  consensus_client = find_client (client);
-  if (NULL == consensus_client)
+  session = sessions_head;
+  while ((session != NULL) && (session->client != client))
   {
+    session = session->next;
+  }
+  if (NULL == session)
+  {
     GNUNET_SERVER_client_disconnect (client);
     return;
   }
-  consensus_client->conclude_requested = GNUNET_YES;
-  send_next (consensus_client);
-
+  session->conclude_requested = GNUNET_YES;
+  send_next (session);
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
+
 /**
+ * Called when a client sends an ack
+ */
+void
+client_ack (void *cls,
+             struct GNUNET_SERVER_Client *client,
+             const struct GNUNET_MessageHeader *message)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "client ack received\n");
+}
+
+/**
  * Task that disconnects from core.
  *
  * @param cls core handle
@@ -538,7 +466,7 @@
   core = (struct GNUNET_CORE_Handle *) cls;
   GNUNET_CORE_disconnect (core);
 
-  GNUNET_log(GNUNET_ERROR_TYPE_INFO, "disconnected from core\n");
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "disconnected from core\n");
 }
 
 
@@ -554,16 +482,14 @@
         sizeof (struct GNUNET_MessageHeader)},
     {&client_conclude, NULL, GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_CONCLUDE,
         sizeof (struct GNUNET_CONSENSUS_ConcludeMessage)},
+    {&client_ack, NULL, GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_ACK,
+        sizeof (struct GNUNET_CONSENSUS_AckMessage)},
     {NULL, NULL, 0, 0}
   };
 
-
   GNUNET_SERVER_add_handlers (srv, handlers);
-
   my_peer = GNUNET_memdup(peer, sizeof (struct GNUNET_PeerIdentity));
-
   GNUNET_SCHEDULER_add_now (&disconnect_core, core);
-
   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "connected to core\n");
 }
 
@@ -583,7 +509,7 @@
     {NULL, 0, 0}
   };
 
-  GNUNET_log(GNUNET_ERROR_TYPE_INFO, "run\n");
+  GNUNET_log(GNUNET_ERROR_TYPE_INFO, "consensus  running\n");
 
   cfg = c;
   srv = server;

Added: gnunet/src/consensus/ibf.c
===================================================================
--- gnunet/src/consensus/ibf.c                          (rev 0)
+++ gnunet/src/consensus/ibf.c  2012-12-05 21:41:09 UTC (rev 25275)
@@ -0,0 +1,244 @@
+/*
+      This file is part of GNUnet
+      (C) 2012 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 2, 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 consensus/ibf.c
+ * @brief implementation of the invertible bloom filter
+ * @author Florian Dold
+ */
+
+#include "platform.h"
+#include "gnunet_common.h"
+#include "ibf.h"
+
+
+struct PureCells
+{
+  int index;
+  struct PureCells *next;
+  struct PureCells *prev;
+};
+
+struct InvertibleBloomFilter
+{
+  /**
+   * How many cells does this IBF have?
+   */
+  int size;
+
+  /**
+   * In how many cells do we hash one element?
+   * Usually 4 or 3.
+   */
+  int hash_num;
+
+  /**
+   * Salt for mingling hashes
+   */
+  int salt;
+
+  /**
+   * How many times has a bucket been hit?
+   * Can be negative, as a result of IBF subtraction.
+   */
+  int8_t *count;
+
+  /**
+   * xor sums of the elements' hash codes, used to identify the elements.
+   */
+  GNUNET_HashCode *id_sum;
+
+  /**
+   * xor sums of the "hash of the hash".
+   */
+  GNUNET_HashCode *hash_sum;
+
+  struct PureCells *pure_head;
+  struct PureCells *pure_tail;
+
+  /**
+   * GNUNET_YES: fresh list is deprecated
+   * GNUNET_NO: fresh list is up to date
+   */
+  int pure_fresh;
+};
+
+
+/**
+ * Create an invertible bloom filter.
+ */
+struct InvertibleBloomFilter *
+ibf_create(int size, int hash_num)
+{
+  struct InvertibleBloomFilter *ibf;
+
+  ibf = GNUNET_malloc (sizeof (struct InvertibleBloomFilter));
+  ibf->count = GNUNET_malloc (size * sizeof uint8_t);
+  ibf->id_sum = GNUNET_malloc (size * sizeof (struct GNUNET_HashCode));
+  ibf->hash_sum = GNUNET_malloc (size * sizeof (struct GNUNET_HashCode));
+  ibf->size = size;
+  ibf->hash_num = hash_num;
+}
+
+
+/**
+ * Insert an element into an IBF.
+ */
+void
+ibf_insert (struct InvertibleBloomFilter *ibf, struct GNUNET_HashCode *id)
+{
+  struct GNUNET_HashCode key;
+  struct GNUNET_HashCode id_hash;
+  int i;
+
+  key = *id;
+  GNUNET_hash (id, sizeof (struct GNUNET_HashCode), &id_hash);
+
+  for (i = 0; i < ibf->hash_num; i++)
+  {
+    int bucket;
+    int j;
+    if ((i != 0) && (i % 16) == 0)
+    {
+      GNUNET_hash (&key, sizeof (struct GNUNET_HashCode), &key);
+    }
+    bucket = hash.bits[i%16] % ibf->size;
+
+    /* count<0 can happen after ibf subtraction, but then no insert should be 
done */
+    GNUNET_assert (ibf->count[bucket] >= 0);
+
+    ibf->count[bucket]++;
+
+    for (j=0; j < 16; j++)
+    {
+      ibf->id_sum.bits[j] ^= &id;
+      ibf->hash_sum.bits[j] ^= &id_hash;
+    }
+
+  }
+}
+
+
+/**
+ * Update the linked list of pure cells, if not fresh anymore
+ */
+void
+update_pure (struct InvertibleBloomFilter *ibf)
+{
+  if (GNUNET_YES == ibf->pure_fresh)
+  {
+    return;
+  }
+
+  ibf->pure_fresh = GNUNET_YES;
+}
+
+/**
+ * Decode and remove an element from the IBF, if possible.
+ *
+ * @param ibf the invertible bloom filter to decode
+ * @param ret_id the hash code of the decoded element, if successful
+ * @param side sign of the cell's count where the decoded element came from.
+ *             A negative sign indicates that the element was recovered 
resides in an IBF
+ *             that was previously subtracted from.
+ * @return GNUNET_YES if decoding an element was successful, GNUNET_NO if the 
IBF is empty,
+ *         GNUNET_SYSERR if the decoding has faile
+ */
+int
+ibf_decode (struct InvertibleBloomFilter *ibf, int *ret_side, struct 
GNUNET_HashCode *ret_id)
+{
+  struct GNUNET_HashCode hash;
+  struct PureCells *pure;
+  int count;
+
+  GNUNET_assert (NULL != ibf);
+  GNUNET_assert (NULL != red_id);
+  GNUNET_assert (NULL != side);
+
+  update_pure (ibf);
+
+  pure = ibf->pure_head;
+  ibf->pure_head = pure->next;
+
+  if (NULL == pure)
+  {
+    int i;
+    for (i = 0; i < ibf->size; i++)
+    {
+      int j;
+      if (0 != ibf->count[i])
+        return GNUNET_SYSERR;
+      for (j = 0; j < 16; ++j)
+        if ((0 != ibf->hash_sum[i].bits[j]) || (0 != ibf->id_sum[i].bits[j]))
+          return GNUNET_SYSERR;
+      return GNUNET_NO;
+    }
+  }
+
+  GNUNET_CRYPTO_hash (ibf->id_sum[pure->idx], sizeof (struct GNUNET_HashCode), 
&hash);
+
+  if (0 == memcmp (&hash, ibf->hash_sum[pure->idx]))
+  {
+    struct GNUNET_HashCode key;
+    int i;
+
+    *ret_side = ibf->count[pure->index];
+    *ret_id = ibf->id_sum[pure->index];
+
+    key = *ibf->id_sum[pure->index];
+
+    /* delete the item from all buckets */
+    for (i = 0; i < ibf->hash_num; i++)
+    {
+      int bucket;
+      int j;
+      if ((i != 0) && (i % 16) == 0)
+      {
+        GNUNET_hash (&key, sizeof (struct GNUNET_HashCode), &key);
+      }
+      bucket = hash.bits[i%16] % ibf->size;
+
+      ibf->count[bucket] -= count;
+
+      for (j=0; j < 16; j++)
+      {
+        ibf->id_sum.bits[j] ^= &id;
+        ibf->hash_sum.bits[j] ^= &id_hash;
+      }
+      return GNUNET_YES;
+  }
+  return GNUNET_SYSERR;
+}
+
+
+
+/**
+ * Subtract ibf2 from ibf1, storing the result in ibf1.
+ * The two IBF's must have the same parameters size and hash_num.
+ *
+ * @return a newly allocated invertible bloom filter
+ */
+void
+ibf_subtract (struct InvertibleBloomFilter *ibf1, struct InvertibleBloomFilter 
*ibf2)
+{
+  /* FIXME */
+}
+

Added: gnunet/src/consensus/ibf.h
===================================================================
--- gnunet/src/consensus/ibf.h                          (rev 0)
+++ gnunet/src/consensus/ibf.h  2012-12-05 21:41:09 UTC (rev 25275)
@@ -0,0 +1,98 @@
+/*
+      This file is part of GNUnet
+      (C) 2012 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 2, 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 consensus/ibf.h
+ * @brief invertible bloom filter
+ * @author Florian Dold
+ */
+
+
+/**
+ * Opaque handle to an invertible bloom filter (IBF).
+ *
+ * An IBF is a counting bloom filter that has the ability to restore
+ * the hashes of its stored elements with high probability.
+ */
+struct InvertibleBloomFilter
+
+/**
+ * Create an invertible bloom filter.
+ *
+ * @param size number of IBF buckets
+ * @param salt salt for mingling hashes, different salt may
+ *        result in less (or more) collisions
+ * @param hash_num number of buckets one element is hashed in
+ * @return the newly created invertible bloom filter
+ */
+struct InvertibleBloomFilter *
+ibf_create(int size, int salt, int hash_num);
+
+/**
+ * Insert an element into an IBF.
+ *
+ * @param ibf the IBF
+ * @param id the element's hash code
+ */
+void
+ibf_insert (struct InvertibleBloomFilter *ibf, GNUNET_HashCode *id);
+
+/**
+ * Subtract ibf2 from ibf1, storing the result in ibf1.
+ * The two IBF's must have the same parameters size and hash_num.
+ */
+void
+ibf_subtract (struct InvertibleBloomFilter *ibf1, struct InvertibleBloomFilter 
*ibf2);
+
+/**
+ * Decode and remove an element from the IBF, if possible.
+ *
+ * @param ibf the invertible bloom filter
+ * @param the id of the element is written to this hash code
+ * @return GNUNET_YES if decoding an element was successful, GNUNET_NO if it 
failed to decode
+ */
+int
+ibf_decode (struct InvertibleBloomFilter *ibf, struct GNUNET_HashCode *ret_id);
+
+
+/**
+ * Create a copy of an IBF, the copy has to be destroyed properly.
+ *
+ * @param ibf the IBF to copy
+ */
+struct InvertibleBloomFilter *
+ibf_dup (struct InvertibleBloomFilter *ibf);
+
+/*
+ibf_hton();
+
+ibf_ntoh();
+*/
+
+/**
+ * Destroy all resources associated with the invertible bloom filter.
+ * No more ibf_*-functions may be called on ibf after calling destroy.
+ *
+ * @param ibf the intertible bloom filter to destroy
+ */
+void
+ibf_destroy (struct InvertibleBloomFilter *ibf);
+

Modified: gnunet/src/consensus/test_consensus.conf
===================================================================
--- gnunet/src/consensus/test_consensus.conf    2012-12-05 21:40:51 UTC (rev 
25274)
+++ gnunet/src/consensus/test_consensus.conf    2012-12-05 21:41:09 UTC (rev 
25275)
@@ -10,7 +10,7 @@
 UNIXPATH = /tmp/gnunet-service-consensus.sock
 UNIX_MATCH_UID = YES
 UNIX_MATCH_GID = YES
-OPTIONS = -LDEBUG
+OPTIONS = -L INFO
 
 
 [transport]
@@ -18,4 +18,8 @@
 
 
 [arm]
-DEFAULTSERVICES = core
+DEFAULTSERVICES = core consensus
+
+
+[testbed]
+OVERLAY_TOPOLOGY = CLIQUE




reply via email to

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