gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] r28794 - in gnunet: doc/man po src src/include src/vectorpr


From: gnunet
Subject: [GNUnet-SVN] r28794 - in gnunet: doc/man po src src/include src/vectorproduct
Date: Thu, 22 Aug 2013 15:41:49 +0200

Author: cfuchs
Date: 2013-08-22 15:41:49 +0200 (Thu, 22 Aug 2013)
New Revision: 28794

Added:
   gnunet/doc/man/gnunet-vectorproduct.1
   gnunet/src/include/gnunet_vectorproduct_service.h
   gnunet/src/vectorproduct/
   gnunet/src/vectorproduct/Makefile.am
   gnunet/src/vectorproduct/gnunet-service-vectorproduct.c
   gnunet/src/vectorproduct/gnunet-vectorproduct.c
   gnunet/src/vectorproduct/gnunet_vectorproduct.h
   gnunet/src/vectorproduct/test_vectorproduct_api.c
   gnunet/src/vectorproduct/test_vectorproduct_api_4peers.c
   gnunet/src/vectorproduct/test_vectorproduct_api_data.conf
   gnunet/src/vectorproduct/test_vectorproduct_api_regression.c
   gnunet/src/vectorproduct/test_vectorproduct_api_regression2.c
   gnunet/src/vectorproduct/vectorproduct.conf.in
   gnunet/src/vectorproduct/vectorproduct_api.c
   gnunet/src/vectorproduct/vectorproduct_testing.h
Modified:
   gnunet/doc/man/Makefile.am
   gnunet/po/POTFILES.in
   gnunet/src/Makefile.am
   gnunet/src/include/gnunet_applications.h
   gnunet/src/include/gnunet_protocols.h
Log:
added vectorproduct protocol definitions
added to be localized files to POTFILES
added (inactive) changes to the src/Makefile.am
added manpage for vectorproduct
added apptype for vectorproduct
added vectorproduct service, client, API and related sources to SVN



Modified: gnunet/doc/man/Makefile.am
===================================================================
--- gnunet/doc/man/Makefile.am  2013-08-22 13:12:26 UTC (rev 28793)
+++ gnunet/doc/man/Makefile.am  2013-08-22 13:41:49 UTC (rev 28794)
@@ -27,6 +27,7 @@
   gnunet-transport.1 \
   gnunet-unindex.1 \
   gnunet-uri.1 \
+  gnunet-vectorproduct.1 \
   gnunet-vpn.1
 
 EXTRA_DIST = ${man_MANS}

Added: gnunet/doc/man/gnunet-vectorproduct.1
===================================================================
--- gnunet/doc/man/gnunet-vectorproduct.1                               (rev 0)
+++ gnunet/doc/man/gnunet-vectorproduct.1       2013-08-22 13:41:49 UTC (rev 
28794)
@@ -0,0 +1,65 @@
+.TH GNUNET\-VECTORPRODUCT 1 "8 Aug 2013" "GNUnet"
+
+.SH NAME
+gnunet\-vectorproduct \- compute a vectorproduct
+
+.SH SYNOPSIS
+.B gnunet\-vectorproduct
+.RI [ options ]
+.br
+
+.SH DESCRIPTION
+\fBgnunet-vectorproduct\fP enables you to compute a vectorproduct across two 
peers \fBAlice\fP and \fBBob\fP.
+
+A client can issue one of two messages to its service:
+.TS
+tab (@);
+l lx.
address@hidden
+A request to compute a vectorproduct with another peer (\fBAlice\fP) 
+T}
address@hidden
+Elements to support a peer in computing a vectorproduct (\fBBob\fP) 
+T}
+.TE
+
+Both requests must share the same SID, which can be an arbitrary string 
identifying the session. SIDs should be unique, however it is sufficient to 
guarantee the uniqueness of the tupel element count and session ID.
+
+\fBAlice\fP\'s client must supply the ASCII encoded peer ID of bob\'s service, 
it will internally be checked by the client for validity. Invalid values here 
result in the client or the service failing the session.
+
+Elements are handed over as signed decimal integers, the element count 
supplied by \fBAlice\fP and \fBBob\fP must match. \fBAlice\fP can also supply a 
mask for these values to her service, which allows partial vector products to 
be computed across the vector. Elements can be masked by setting their the 
corresponding mask element to zero, any other value means the element will not 
be masked. \fBAlice\fP\'s client will also mask all 0-values to avoid 
information leakage to \fBBob\fP. 
+
+The protocol by definition relies on \fBAlice\fP and \fBBob\fP being benign, 
thus \fBBob\fP can arbitrarily falsify his information. Both peers collaborate 
to achieve a correct result. 
+
+.SH OPTIONS
+.B
+.IP "\-e ELEMENTS, \-\-elements=ELEMENTS"
+The element-vector the vectorproduct should be computed over in signed decimal 
form, eg: \"42,1,-3,3,7\". Zero value elements will be automatically masked.
+.B
+.IP "\-m MASK, \-\-mask=MASK"
+Elements in the vector can be masked. There must be at least two elements left 
in the vector to compute a vectorproduct. Non-Zero values indicate an element 
is not maskes.
+.B
+.IP "\-k KEY, \-\-key=KEY"
+The session key, a shared string of arbitrary length from which the SID will 
be generated
+.B
+.IP "\-c FILENAME,  \-\-config=FILENAME"
+Use the configuration file FILENAME.
+.B
+.IP "\-p PEERID, \-\-peer=PEERID"
+The remote peer\'s ASCII-armored gnunet-peer ID as output by gnunet-peerinfo. 
If this option is not given, the peer will take the \fBBob\fP\'s role.
+.B
+.IP "\-h, \-\-help"
+Print short help on options.
+.B
+.IP "\-L LOGLEVEL, \-\-loglevel=LOGLEVEL"
+Use LOGLEVEL for logging.  Valid values are DEBUG, INFO, WARNING and ERROR.
+.B
+.IP "\-v, \-\-version"
+Print GNUnet version number.
+
+
+.SH BUGS
+Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending 
electronic mail to <address@hidden>
+
+.SH SEE ALSO
+gnunet\-peerinfo(1)

Modified: gnunet/po/POTFILES.in
===================================================================
--- gnunet/po/POTFILES.in       2013-08-22 13:12:26 UTC (rev 28793)
+++ gnunet/po/POTFILES.in       2013-08-22 13:41:49 UTC (rev 28794)
@@ -343,3 +343,6 @@
 src/mesh/mesh_protocol_enc.h
 src/testbed/testbed_api.h
 src/testbed/testbed_api_operations.h
+src/vectorproduct/vectorproduct_api.c
+src/vectorproduct/gnunet-service-vectorproduct.c
+src/vectorproduct/gnunet-vectorproduct.c

Modified: gnunet/src/Makefile.am
===================================================================
--- gnunet/src/Makefile.am      2013-08-22 13:12:26 UTC (rev 28793)
+++ gnunet/src/Makefile.am      2013-08-22 13:41:49 UTC (rev 28794)
@@ -7,10 +7,12 @@
  TESTBED = testbed
  CONSENSUS = consensus
  EXPERIMENTATION = experimentation
+ VECTORPRODUCT = vectorproduct
 endif
 
 if HAVE_EXPERIMENTAL
  EXP_DIR = dv $(CONSENSUS) $(EXPERIMENTATION) 
+#note: vectorproduct is not being listed here yet as the crypto is being 
reworked at the moment
 endif
 
 if HAVE_MYSQL

Modified: gnunet/src/include/gnunet_applications.h
===================================================================
--- gnunet/src/include/gnunet_applications.h    2013-08-22 13:12:26 UTC (rev 
28793)
+++ gnunet/src/include/gnunet_applications.h    2013-08-22 13:41:49 UTC (rev 
28794)
@@ -76,12 +76,15 @@
  */
 #define GNUNET_APPLICATION_TYPE_CONSENSUS 18
 
-
 /**
  * Set. Used for two-peer set operations implemented using stream.
  */
 #define GNUNET_APPLICATION_TYPE_SET 19
 
+/**
+ * Vectorproduct. Used for two-peer vectorproduct operations
+ */
+#define GNUNET_APPLICATION_TYPE_VECTORPRODUCT 20
 
 #if 0                           /* keep Emacsens' auto-indent happy */
 {

Modified: gnunet/src/include/gnunet_protocols.h
===================================================================
--- gnunet/src/include/gnunet_protocols.h       2013-08-22 13:12:26 UTC (rev 
28793)
+++ gnunet/src/include/gnunet_protocols.h       2013-08-22 13:41:49 UTC (rev 
28794)
@@ -1905,11 +1905,42 @@
 #define GNUNET_MESSAGE_TYPE_IDENTITY_DELETE 631
 
 
+/*******************************************************************************
+ * VECTORPRODUCT message types
+ 
******************************************************************************/
+
 /**
- *  Next available: 640
+ * Client -> Vector-Product Service request message
  */
+#define GNUNET_MESSAGE_TYPE_VECTORPRODUCT_CLIENT_TO_ALICE 640
 
+/**
+ * Client -> Vector-Product Service request message
+ */
+#define GNUNET_MESSAGE_TYPE_VECTORPRODUCT_CLIENT_TO_BOB 641
 
+/**
+ * Vector-Product Service request -> remote VP Service
+ */
+#define GNUNET_MESSAGE_TYPE_VECTORPRODUCT_ALICE_TO_BOB 642
+
+/**
+ * remote Vector-Product Service response -> requesting VP Service
+ */
+#define GNUNET_MESSAGE_TYPE_VECTORPRODUCT_BOB_TO_ALICE 643
+
+/**
+ * Vector-Product Service response -> Client
+ */
+#define GNUNET_MESSAGE_TYPE_VECTORPRODUCT_SERVICE_TO_CLIENT 644
+
+
+
+/**
+ * Next available: 650
+ */
+
+
 /* WIP: no numbers assigned yet */
 
 
/*******************************************************************************

Added: gnunet/src/include/gnunet_vectorproduct_service.h
===================================================================
--- gnunet/src/include/gnunet_vectorproduct_service.h                           
(rev 0)
+++ gnunet/src/include/gnunet_vectorproduct_service.h   2013-08-22 13:41:49 UTC 
(rev 28794)
@@ -0,0 +1,265 @@
+/*
+      This file is part of GNUnet.
+      (C) 2013 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 include/gnunet_vectorproduct_service.h
+ * @brief API to the vectorproduct service
+ * @author Christian M. Fuchs
+ * @author Gaurav Kukreja
+ */
+#ifndef GNUNET_VECTORPRODUCT_SERVICE_H
+#define GNUNET_VECTORPRODUCT_SERVICE_H
+#define GCRYPT_NO_DEPRECATED
+// including gcrypt crashes netbeans after the next restart...
+#include <gcrypt.h>
+
+#ifdef __cplusplus
+extern "C" {
+#if 0                           /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+/**
+ * Version of the vectorproduct API.
+ */
+#define GNUNET_VECTORPRODUCT_VERSION 0x00000042
+
+/**
+ * Message type passed from client to service 
+ * to initiate a request or responder role
+ */
+struct GNUNET_VECTORPRODUCT_client_request {
+  /**
+   * GNUNET message header
+   */
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * how many elements the vector in payload contains
+   */
+  uint16_t element_count GNUNET_PACKED; 
+
+  /**
+   * how many bytes the mask has
+   */
+  uint16_t mask_length GNUNET_PACKED;
+  
+  /**
+   * the transaction/session key used to identify a session
+   */
+  struct GNUNET_HashCode key;
+
+  /**
+   * the identity of a remote peer we want to communicate with
+   */
+  struct GNUNET_PeerIdentity peer;
+
+  /**
+   * followed by long vector[element_count] | [unsigned char mask[mask_bytes]]
+   */
+};
+
+/**
+ * Message type passed from service client
+ * to finalize a session as requester or responder
+ */
+struct GNUNET_VECTORPRODUCT_client_response {
+  /**
+   * GNUNET message header
+   */
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * 0 if no product attached
+   */
+  uint32_t product_length GNUNET_PACKED;
+
+  /**
+   * the transaction/session key used to identify a session
+   */
+  struct GNUNET_HashCode key;
+
+  /**
+   * the identity of a remote peer we want to communicate with
+   */
+  struct GNUNET_PeerIdentity peer;
+
+  /**
+   * followed by product of length product_length (or nothing)
+   */
+};
+
+enum GNUNET_VECTORPRODUCT_ResponseStatus {
+  GNUNET_VECTORPRODUCT_Status_Success = 0,
+  GNUNET_VECTORPRODUCT_Status_Failure,
+  GNUNET_VECTORPRODUCT_Status_Timeout,
+  GNUNET_VECTORPRODUCT_Status_InvalidResponse,
+  GNUNET_VECTORPRODUCT_Status_ServiceDisconnected
+};
+
+struct GNUNET_VECTORPRODUCT_Handle {
+  /**
+   * Our configuration.
+   */
+  const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+  /**
+   * Current connection to the vectorproduct service.
+   */
+  struct GNUNET_CLIENT_Connection *client;
+
+  /**
+   * Handle for statistics.
+   */
+  struct GNUNET_STATISTICS_Handle *stats;
+
+  /**
+   * Current head of priority queue.
+   */
+  struct GNUNET_VECTORPRODUCT_QueueEntry *queue_head;
+
+  /**
+   * Current tail of priority queue.
+   */
+  struct GNUNET_VECTORPRODUCT_QueueEntry *queue_tail;
+
+  /**
+   * Are we currently trying to receive from the service?
+   */
+  int in_receive;
+
+  /**
+   * Current transmit handle.
+   */
+  struct GNUNET_CLIENT_TransmitHandle *th;
+
+  /**
+   * TODO: What else should/could go here?
+   */
+};
+
+typedef void (*GNUNET_VECTORPRODUCT_ResponseMessageHandler) (void *cls,
+        const struct GNUNET_MessageHeader *msg,
+        enum GNUNET_VECTORPRODUCT_ResponseStatus status);
+
+/**
+ * Continuation called to notify client about result of the
+ * operation.
+ *
+ * @param cls closure
+ * @param success GNUNET_SYSERR on failure (including timeout/queue drop)
+ *                GNUNET_NO if content was already there
+ *                GNUNET_YES (or other positive value) on success
+ * @param msg NULL on success, otherwise an error message
+ */
+typedef void (*GNUNET_VECTORPRODUCT_ContinuationWithStatus) (void *cls,
+        const struct GNUNET_HashCode * key,
+        enum GNUNET_VECTORPRODUCT_ResponseStatus status);
+/**
+ * Process a datum that was stored in the vectorproduct.
+ * 
+ * @param cls closure
+ * @param key Sessioon key
+ * @param peer PeerID of the peer with whom the scalar product was calculated.
+ * @param status Status of the request
+ * @param size Size of the received message
+ * @param data Pointer to the data
+ * @param type Type of data
+ */
+typedef void (*GNUNET_VECTORPRODUCT_DatumProcessor) (void *cls,
+        const struct GNUNET_HashCode * key,
+        const struct GNUNET_PeerIdentity * peer,
+        enum GNUNET_VECTORPRODUCT_ResponseStatus status,
+        const struct GNUNET_VECTORPRODUCT_client_response *msg);
+
+/**
+ * Request the Scalar Product Evaluation
+ * 
+ * @param h handle to the master context
+ * @param key Session key - unique to the requesting client
+ * @param peer PeerID of the other peer
+ * @param element_count Number of elements in the vector
+ * @param mask_bytes number of bytes in the mask
+ * @param elements Array of elements of the vector
+ * @param mask Array of the mask
+ * @param timeout Relative timeout for the operation
+ * @param cont Callback function
+ * @param cont_cls Closure for the callback function
+ */
+struct GNUNET_VECTORPRODUCT_QueueEntry *
+GNUNET_VECTORPRODUCT_request(struct GNUNET_VECTORPRODUCT_Handle *h,
+        const struct GNUNET_HashCode * key,
+        const struct GNUNET_PeerIdentity *peer,
+        uint16_t element_count,
+        uint16_t mask_bytes,
+        int32_t * elements, const unsigned char * mask,
+        struct GNUNET_TIME_Relative timeout,
+        GNUNET_VECTORPRODUCT_DatumProcessor cont,
+        void *cont_cls);
+
+/**
+ * Called by the responder client to prepare response
+ * 
+ * @param h handle to the master context
+ * @param key Session key - unique to the requesting client
+ * @param element_count Number of elements in the vector
+ * @param mask_bytes number of bytes in the mask
+ * @param elements Array of elements of the vector
+ * @param mask Array of the mask
+ * @param timeout Relative timeout for the operation
+ * @param cont Callback function
+ * @param cont_cls Closure for the callback function
+ */
+struct GNUNET_VECTORPRODUCT_QueueEntry *
+GNUNET_VECTORPRODUCT_prepare_response(struct GNUNET_VECTORPRODUCT_Handle *h,
+        const struct GNUNET_HashCode * key,
+        uint16_t element_count,
+        int32_t* elements,
+        struct GNUNET_TIME_Relative timeout,
+        GNUNET_VECTORPRODUCT_ContinuationWithStatus cont,
+        void *cont_cls);
+
+/**
+ * Connect to the vectorproduct service.
+ *
+ * @param cfg configuration to use
+ * @return handle to use to access the service
+ */
+struct GNUNET_VECTORPRODUCT_Handle *
+GNUNET_VECTORPRODUCT_connect(const struct GNUNET_CONFIGURATION_Handle * cfg);
+
+/**
+ * Disconnect from the vectorproduct service.
+ * 
+ * @param h handle to the vectorproduct
+ */
+void
+GNUNET_VECTORPRODUCT_disconnect(struct GNUNET_VECTORPRODUCT_Handle * h);
+
+
+#if 0                           /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif

Added: gnunet/src/vectorproduct/Makefile.am
===================================================================
--- gnunet/src/vectorproduct/Makefile.am                                (rev 0)
+++ gnunet/src/vectorproduct/Makefile.am        2013-08-22 13:41:49 UTC (rev 
28794)
@@ -0,0 +1,97 @@
+SUBDIRS = .
+
+INCLUDES = \
+  -I$(top_srcdir)/src/include \
+  -I$(top_srcdir)
+
+AM_CPPFLAGS = \
+  $(GNUNET_CPPFLAGS)
+
+# Set this variable if you are using GNUNET libraries for all programs and
+# libraries. You don't then need to target-specific _LDFLAGS with 
GNUNET_LDFLAGS
+# AM_LDFLAGS = \
+#   $(GNUNET_LDFLAGS) \
+#   $(WINFLAGS) \
+#   -export-dynamic
+
+lib_LTLIBRARIES = libgnunetvectorproduct.la
+
+pkgcfgdir= $(prefix)/share/gnunet/config.d/
+
+libexecdir= $(prefix)/lib/gnunet/libexec/
+
+libgnunetvectorproduct_la_SOURCES = \
+  vectorproduct_api.c 
+libgnunetvectorproduct_la_LIBADD = \
+  -lgnunetutil -lgcrypt -lgnunetstatistics
+libgnunetvectorproduct_la_LDFLAGS = \
+  $(GNUNET_LDFLAGS)  $(WINFLAGS) \
+  -version-info 0:0:0
+
+
+bin_PROGRAMS = gnunet-vectorproduct 
+
+libexec_PROGRAMS = gnunet-service-vectorproduct
+
+check_PROGRAMS = \
+       test_vectorproduct_api_regression \
+       test_vectorproduct_api \
+       test_vectorproduct_api_4peers
+#FIXME unfinished
+#test_vectorproduct_api_regression2 
+
+TESTS = $(check_PROGRAMS)
+
+gnunet_service_vectorproduct_SOURCES = \
+  gnunet-service-vectorproduct.c
+gnunet_service_vectorproduct_LDADD = \
+  -lgnunetutil -lgnunettransport -lgnunetcore -lgnunetmesh -lgnunetdht 
-lgcrypt \
+  $(INTLLIBS) 
+gnunet_service_vectorproduct_LDFLAGS = \
+  $(GNUNET_LDFLAGS)  $(WINFLAGS) -export-dynamic 
+
+gnunet_vectorproduct_SOURCES = \
+  gnunet-vectorproduct.c
+gnunet_vectorproduct_LDADD = \
+  $(top_builddir)/src/vectorproduct/libgnunetvectorproduct.la \
+  -lgnunetutil -lgcrypt \
+  $(INTLLIBS) 
+gnunet_vectorproduct_LDFLAGS = \
+ $(GNUNET_LDFLAGS) $(WINFLAGS) -export-dynamic 
+
+
+test_vectorproduct_api_SOURCES = \
+  test_vectorproduct_api.c
+test_vectorproduct_api_LDADD = \
+  $(top_builddir)/src/vectorproduct/libgnunetvectorproduct.la \
+  -lgnunetutil -lgcrypt -lgnunetstatistics -lgnunettestbed
+test_vectorproduct_api_LDFLAGS = \
+ $(GNUNET_LDFLAGS)  $(WINFLAGS) -export-dynamic
+
+#FIXME unfinished
+#test_vectorproduct_api_regression2_SOURCES = \
+#      test_vectorproduct_api_regression2.c
+#test_vectorproduct_api_regression2_LDADD = \
+#  $(top_builddir)/src/vectorproduct/libgnunetvectorproduct.la \
+#  -lgnunetutil -lgcrypt -lgnunetstatistics -lgnunettestbed
+#test_vectorproduct_api_regression2_LDFLAGS = \
+# $(GNUNET_LDFLAGS)  $(WINFLAGS) -export-dynamic
+
+test_vectorproduct_api_regression_SOURCES = \
+        test_vectorproduct_api_regression.c
+test_vectorproduct_api_regression_LDADD = \
+  $(top_builddir)/src/vectorproduct/libgnunetvectorproduct.la \
+  -lgnunetutil -lgcrypt -lgnunetstatistics -lgnunettestbed
+test_vectorproduct_api_regression_LDFLAGS = \
+ $(GNUNET_LDFLAGS)  $(WINFLAGS) -export-dynamic
+
+test_vectorproduct_api_4peers_SOURCES = \
+ test_vectorproduct_api_4peers.c
+test_vectorproduct_api_4peers_LDADD = \
+  $(top_builddir)/src/vectorproduct/libgnunetvectorproduct.la \
+  -lgnunetutil -lgcrypt -lgnunetstatistics -lgnunettestbed
+test_vectorproduct_api_4peers_LDFLAGS = \
+ $(GNUNET_LDFLAGS)  $(WINFLAGS) -export-dynamic
+ 
+ pkgcfg_DATA = vectorproduct.conf 
+ 

Added: gnunet/src/vectorproduct/gnunet-service-vectorproduct.c
===================================================================
--- gnunet/src/vectorproduct/gnunet-service-vectorproduct.c                     
        (rev 0)
+++ gnunet/src/vectorproduct/gnunet-service-vectorproduct.c     2013-08-22 
13:41:49 UTC (rev 28794)
@@ -0,0 +1,2067 @@
+/*
+     This file is part of GNUnet.
+     (C) 2013 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 vectorproduct/gnunet-service-vectorproduct.c
+ * @brief vectorproduct service implementation
+ * @author Christian M. Fuchs
+ */
+#include <limits.h>
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_core_service.h"
+#include "gnunet_mesh_service.h"
+#include "gnunet_applications.h"
+#include "gnunet_protocols.h"
+#include "gnunet_vectorproduct_service.h"
+#include "gnunet_vectorproduct.h"
+
+///////////////////////////////////////////////////////////////////////////////
+//                      Global Variables
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Handle to the core service (NULL until we've connected to it).
+ */
+static struct GNUNET_CORE_Handle *my_core;
+
+/**
+ * Handle to the core service (NULL until we've connected to it).
+ */
+static struct GNUNET_MESH_Handle *my_mesh;
+
+/**
+ * The identity of this host.
+ */
+static struct GNUNET_PeerIdentity me;
+
+/**
+ * Service's own public key represented as string
+ */
+static unsigned char * my_pubkey_external;
+
+/**
+ * Service's own public key represented as string
+ */
+static uint16_t my_pubkey_external_length = 0;
+
+/**
+ * Service's own n
+ */
+static gcry_mpi_t my_n;
+
+/**
+ * Service's own n^2 (kept for performance)
+ */
+static gcry_mpi_t my_nsquare;
+
+/**
+ * Service's own public exponent
+ */
+static gcry_mpi_t my_g;
+
+/**
+ * Service's own private multiplier
+ */
+static gcry_mpi_t my_mu;
+
+/**
+ * Service's own private exponent
+ */
+static gcry_mpi_t my_lambda;
+
+/**
+ * Head of our double linked list for client-requests sent to us. 
+ * for all of these elements we calculate a vector product with a remote peer
+ * split between service->service and client->service for simplicity
+ */
+static struct ServiceSession * from_client_head;
+/**
+ * Tail of our double linked list for client-requests sent to us. 
+ * for all of these elements we calculate a vector product with a remote peer
+ * split between service->service and client->service for simplicity
+ */
+static struct ServiceSession * from_client_tail;
+
+/**
+ * Head of our double linked list for service-requests sent to us. 
+ * for all of these elements we help the requesting service in calculating a 
vector product
+ * split between service->service and client->service for simplicity
+ */
+static struct ServiceSession * from_service_head;
+
+/**
+ * Tail of our double linked list for service-requests sent to us. 
+ * for all of these elements we help the requesting service in calculating a 
vector product
+ * split between service->service and client->service for simplicity
+ */
+static struct ServiceSession * from_service_tail;
+
+/**
+ * Certain events (callbacks for server & mesh operations) must not be queued 
after shutdown.
+ */
+static int do_shutdown;
+
+///////////////////////////////////////////////////////////////////////////////
+//                      Helper Functions
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Generates an Paillier private/public keyset and extracts the values using 
libgrcypt only
+ */
+static void
+generate_keyset ()
+{
+  gcry_sexp_t gen_parms;
+  gcry_sexp_t key;
+  gcry_sexp_t tmp_sexp;
+  gcry_mpi_t p;
+  gcry_mpi_t q;
+  gcry_mpi_t tmp1;
+  gcry_mpi_t tmp2;
+  gcry_mpi_t gcd;
+
+  size_t erroff = 0;
+
+  // we can still use the RSA keygen for generating p,q,n, but using e is 
pointless.
+  GNUNET_assert (0 == gcry_sexp_build (&gen_parms, &erroff,
+                                       "(genkey(rsa(nbits %d)(rsa-use-e 
3:257)))",
+                                       KEYBITS));
+
+  GNUNET_assert (0 == gcry_pk_genkey (&key, gen_parms));
+  gcry_sexp_release (gen_parms);
+
+  // get n and d of our publickey as MPI  
+  tmp_sexp = gcry_sexp_find_token (key, "n", 0);
+  GNUNET_assert (tmp_sexp);
+  my_n = gcry_sexp_nth_mpi (tmp_sexp, 1, GCRYMPI_FMT_USG);
+  gcry_sexp_release (tmp_sexp);
+  tmp_sexp = gcry_sexp_find_token (key, "p", 0);
+  GNUNET_assert (tmp_sexp);
+  p = gcry_sexp_nth_mpi (tmp_sexp, 1, GCRYMPI_FMT_USG);
+  gcry_sexp_release (tmp_sexp);
+  tmp_sexp = gcry_sexp_find_token (key, "q", 0);
+  GNUNET_assert (tmp_sexp);
+  q = gcry_sexp_nth_mpi (tmp_sexp, 1, GCRYMPI_FMT_USG);
+  gcry_sexp_release (key);
+
+  tmp1 = gcry_mpi_new (0);
+  tmp2 = gcry_mpi_new (0);
+  gcd = gcry_mpi_new (0);
+  my_g = gcry_mpi_new (0);
+  my_mu = gcry_mpi_new (0);
+  my_nsquare = gcry_mpi_new (0);
+  my_lambda = gcry_mpi_new (0);
+
+  // calculate lambda
+  // lambda = \frac{(p-1)*(q-1)}{gcd(p-1,q-1)}
+  gcry_mpi_sub_ui (tmp1, p, 1);
+  gcry_mpi_sub_ui (tmp2, q, 1);
+  gcry_mpi_gcd (gcd, tmp1, tmp2);
+  gcry_mpi_set (my_lambda, tmp1);
+  gcry_mpi_mul (my_lambda, my_lambda, tmp2);
+  gcry_mpi_div (my_lambda, NULL, my_lambda, gcd, 0);
+
+  // generate a g
+  gcry_mpi_mul (my_nsquare, my_n, my_n);
+  do
+    {
+      // find a matching g
+      do
+        {
+          gcry_mpi_randomize (my_g, KEYBITS * 2, GCRY_WEAK_RANDOM);
+          // g must be smaller than n^2
+          if (0 >= gcry_mpi_cmp (my_g, my_nsquare))
+            continue;
+
+          // g must have gcd == 1 with n^2
+          gcry_mpi_gcd (gcd, my_g, my_nsquare);
+        }
+      while (gcry_mpi_cmp_ui (gcd, 1));
+
+      // is this a valid g?
+      // if so, gcd(((g^lambda mod n^2)-1 )/n, n) = 1
+      gcry_mpi_powm (tmp1, my_g, my_lambda, my_nsquare);
+      gcry_mpi_sub_ui (tmp1, tmp1, 1);
+      gcry_mpi_div (tmp1, NULL, tmp1, my_n, 0);
+      gcry_mpi_gcd (gcd, tmp1, my_n);
+    }
+  while (gcry_mpi_cmp_ui (gcd, 1));
+
+  // calculate our mu based on g and n.
+  // mu = (((g^lambda mod n^2)-1 )/n)^-1 mod n
+  gcry_mpi_invm (my_mu, tmp1, my_n);
+
+  GNUNET_assert (0 == gcry_sexp_build (&key, &erroff,
+                                       "(public-key (paillier (n %M)(g %M)))",
+                                       my_n, my_g));
+
+  // get the length of this sexpression
+  my_pubkey_external_length = gcry_sexp_sprint (key,
+                                                GCRYSEXP_FMT_CANON,
+                                                NULL,
+                                                UINT16_MAX);
+
+  GNUNET_assert (my_pubkey_external_length > 0);
+  my_pubkey_external = GNUNET_malloc (my_pubkey_external_length);
+
+  // convert the sexpression to canonical format
+  gcry_sexp_sprint (key,
+                    GCRYSEXP_FMT_CANON,
+                    my_pubkey_external,
+                    my_pubkey_external_length);
+
+  gcry_sexp_release (key);
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Generated key set with key length 
%d bits.\n"), KEYBITS);
+}
+
+
+/**
+ * If target != size, move target bytes to the
+ * end of the size-sized buffer and zero out the
+ * first target-size bytes.
+ *
+ * @param buf original buffer
+ * @param size number of bytes in the buffer
+ * @param target target size of the buffer
+ */
+static void
+adjust (unsigned char *buf, size_t size, size_t target)
+{
+  if (size < target)
+    {
+      memmove (&buf[target - size], buf, size);
+      memset (buf, 0, target - size);
+    }
+}
+
+
+/**
+ * encrypts an element using the paillier crypto system
+ * 
+ * @param c ciphertext (output)
+ * @param m plaintext
+ * @param g the public base
+ * @param r random base (optional) gets generated and if not NULL but 
uninitialized
+ * @param n the module from which which r is chosen (Z*_n)
+ * @param n_square the module for encryption, for performance reasons.
+ */
+static void
+encrypt_element (gcry_mpi_t c, gcry_mpi_t m, gcry_mpi_t g, gcry_mpi_t r, 
gcry_mpi_t n, gcry_mpi_t n_square)
+{
+#ifndef DISABLE_CRYPTO
+  gcry_mpi_t tmp;
+  int release_r = GNUNET_NO;
+
+  GNUNET_assert (tmp = gcry_mpi_new (0));
+  if (NULL == r)
+    {
+      GNUNET_assert (r = gcry_mpi_new (0));
+      release_r = GNUNET_YES;
+
+      while (0 <= gcry_mpi_cmp (r, n) || 0 >= gcry_mpi_cmp_ui (r, 1))
+        {
+          gcry_mpi_randomize (r, KEYBITS, GCRY_WEAK_RANDOM);
+          // r must be 1 < r < n
+        }
+    }
+
+
+  gcry_mpi_powm (c, g, m, n_square);
+  gcry_mpi_powm (tmp, r, n, n_square);
+  gcry_mpi_mulm (c, tmp, c, n_square);
+
+  gcry_mpi_release (tmp);
+  if (GNUNET_YES == release_r)
+    gcry_mpi_release (r);
+#else
+  gcry_mpi_set (c, m);
+#endif
+}
+
+
+/**
+ * decrypts an element using the paillier crypto system
+ * 
+ * @param m plaintext (output)
+ * @param c the ciphertext
+ * @param mu the modifier to correct encryption
+ * @param lambda the private exponent
+ * @param n the outer module for decryption
+ * @param n_square the inner module for decryption
+ */
+static void
+decrypt_element (gcry_mpi_t m, gcry_mpi_t c, gcry_mpi_t mu, gcry_mpi_t lambda, 
gcry_mpi_t n, gcry_mpi_t n_square)
+{
+#ifndef DISABLE_CRYPTO
+  gcry_mpi_powm (m, c, lambda, n_square);
+  gcry_mpi_sub_ui (m, m, 1);
+  gcry_mpi_div (m, NULL, m, n, 0);
+  gcry_mpi_mulm (m, m, mu, n);
+#else
+  gcry_mpi_set (m, c);
+#endif
+}
+
+
+/**
+ * computes the square sum over a vector of a given length.
+ * 
+ * @param vector the vector to encrypt
+ * @param length the length of the vector
+ * @return an MPI value containing the calculated sum, never NULL
+ */
+static gcry_mpi_t
+compute_square_sum (gcry_mpi_t * vector, uint16_t length)
+{
+  gcry_mpi_t elem;
+  gcry_mpi_t sum;
+  int32_t i;
+
+  GNUNET_assert (sum = gcry_mpi_new (0));
+  GNUNET_assert (elem = gcry_mpi_new (0));
+
+  // calculare E(sum (ai ^ 2), publickey)
+  for (i = 0; i < length; i++)
+    {
+      gcry_mpi_mul (elem, vector[i], vector[i]);
+      gcry_mpi_add (sum, sum, elem);
+    }
+  gcry_mpi_release (elem);
+
+  return sum;
+}
+
+
+/**
+ * Primitive callback for copying over a message, as they
+ * usually are too complex to be handled in the callback itself.
+ * clears a session-callback, if a session was handed over and the transmit 
handle was stored
+ * 
+ * @param cls the message object
+ * @param size the size of the buffer we got
+ * @param buf the buffer to copy the message to
+ * @return 0 if we couldn't copy, else the size copied over
+ */
+static size_t
+do_send_message (void *cls, size_t size, void *buf)
+{
+  struct MessageObject * info = cls;
+  struct GNUNET_MessageHeader * msg;
+  size_t written = 0;
+
+  GNUNET_assert (info);
+  msg = info->msg;
+  GNUNET_assert (msg);
+  GNUNET_assert (buf);
+
+  if (ntohs (msg->size) == size)
+    {
+      memcpy (buf, msg, size);
+      written = size;
+    }
+
+  // reset the transmit handle, if necessary
+  if (info->transmit_handle)
+    *info->transmit_handle = NULL;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Sent a message of type %hu.\n"), 
ntohs (msg->type));
+  GNUNET_free(msg);
+  GNUNET_free(info);
+  return written;
+}
+
+
+/**
+ * initializes a new vector with fresh MPI values (=0) of a given length
+ * 
+ * @param length of the vector to create
+ * @return the initialized vector, never NULL
+ */
+static gcry_mpi_t *
+initialize_mpi_vector (uint16_t length)
+{
+  uint32_t i;
+  gcry_mpi_t * output = GNUNET_malloc (sizeof (gcry_mpi_t) * length);
+
+  for (i = 0; i < length; i++)
+    GNUNET_assert (NULL != (output[i] = gcry_mpi_new (0)));
+  return output;
+}
+
+
+/**
+ * permutes an MPI vector according to the given permutation vector
+ * 
+ * @param vector the vector to permuted
+ * @param perm the permutation to use
+ * @param length the length of the vectors
+ * @return the permuted vector (same as input), never NULL
+ */
+static gcry_mpi_t *
+permute_vector (gcry_mpi_t * vector,
+                unsigned int * perm,
+                uint32_t length)
+{
+  gcry_mpi_t tmp[length];
+  uint32_t i;
+
+  GNUNET_assert (length > 0);
+
+  // backup old layout
+  memcpy (tmp, vector, length * sizeof (gcry_mpi_t));
+
+  // permute vector according to given 
+  for (i = 0; i < length; i++)
+    vector[i] = tmp[perm[i]];
+
+  return vector;
+}
+
+
+/**
+ * Populate a vector with random integer values and convert them to 
+ * 
+ * @param length the length of the vector we must generate
+ * @return an array of MPI values with random values
+ */
+static gcry_mpi_t *
+generate_random_vector (uint16_t length)
+{
+  gcry_mpi_t * random_vector;
+  int32_t value;
+  uint32_t i;
+
+  random_vector = initialize_mpi_vector (length);
+  for (i = 0; i < length; i++)
+    {
+      value = (int32_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 
UINT32_MAX);
+
+      // long to gcry_mpi_t
+      if (value < 0)
+        gcry_mpi_sub_ui (random_vector[i],
+                         random_vector[i],
+                         -value);
+      else
+        random_vector[i] = gcry_mpi_set_ui (random_vector[i], value);
+    }
+
+  return random_vector;
+}
+
+
+/**
+ * Finds a not terminated client/service session in the 
+ * given DLL based on session key, element count and state.
+ * 
+ * @param tail - the tail of the DLL
+ * @param my - the session to compare it to
+ * @return a pointer to a matching session, 
+ *         else NULL
+ */
+static struct ServiceSession *
+find_matching_session (struct ServiceSession * tail,
+                       struct GNUNET_HashCode * key,
+                       uint16_t element_count,
+                       enum SessionState * state,
+                       const struct GNUNET_PeerIdentity * peerid)
+{
+  struct ServiceSession * curr;
+
+  for (curr = tail; NULL != curr; curr = curr->prev)
+    {
+      // if the key matches, and the element_count is same
+      if ((!memcmp (&curr->key, key, sizeof (struct GNUNET_HashCode)))
+          && (curr->element_count == element_count))
+        {
+          // if incoming state is NULL OR is same as state of the queued 
request
+          if ((NULL == state) || (curr->state == *state))
+            {
+              // if peerid is NULL OR same as the peer Id in the queued request
+              if ((NULL == peerid)
+                  || (!memcmp (&curr->peer, peerid, sizeof (struct 
GNUNET_PeerIdentity))))
+                // matches and is not an already terminated session
+                return curr;
+            }
+        }
+    }
+
+  return NULL;
+}
+
+
+static void
+destroy_tunnel (void *cls,
+                const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct ServiceSession * session = cls;
+
+  if (session->tunnel)
+    {
+      GNUNET_MESH_tunnel_destroy (session->tunnel);
+      session->tunnel = NULL;
+    }
+  session->service_transmit_handle = NULL;
+  // we need to set this to NULL so there is no problem with double-cancel 
later on.
+}
+
+
+static void
+free_session (struct ServiceSession * session)
+{
+  int i;
+
+  if (FINALIZED != session->state)
+    {
+      if (session->a)
+        {
+          for (i = 0; i < session->used_element_count; i++)
+            gcry_mpi_release (session->a[i]);
+
+          GNUNET_free (session->a);
+        }
+      if (session->product)
+        gcry_mpi_release (session->product);
+
+      if (session->remote_pubkey)
+        gcry_sexp_release (session->remote_pubkey);
+
+      GNUNET_free_non_null (session->vector);
+    }
+
+  GNUNET_free (session);
+}
+///////////////////////////////////////////////////////////////////////////////
+//                      Event and Message Handlers
+///////////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * A client disconnected. 
+ * 
+ * Remove the associated session(s), release datastructures 
+ * and cancel pending outgoing transmissions to the client.
+ * if the session has not yet completed, we also cancel Alice's request to Bob.
+ *
+ * @param cls closure, NULL
+ * @param client identification of the client
+ */
+static void
+handle_client_disconnect (void *cls,
+                          struct GNUNET_SERVER_Client
+                          * client)
+{
+  struct ServiceSession * elem;
+  struct ServiceSession * next;
+
+  // start from the tail, old stuff will be there...
+  for (elem = from_client_head; NULL != elem; elem = next)
+    {
+      next = elem->next;
+      if (elem->client != client)
+        continue;
+
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Client (%p) disconnected from 
us.\n"), client);
+      GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, elem);
+
+      if (!(elem->role == BOB && elem->state == FINALIZED))
+        {
+          //we MUST terminate any client message underway
+          if (elem->service_transmit_handle && elem->tunnel)
+            GNUNET_MESH_notify_transmit_ready_cancel 
(elem->service_transmit_handle);
+          if (elem->tunnel && elem->state == WAITING_FOR_RESPONSE_FROM_SERVICE)
+            destroy_tunnel (elem, NULL);
+        }
+      free_session (elem);
+    }
+}
+
+
+/**
+ * Notify the client that the session has succeeded or failed completely.
+ * This message gets sent to 
+ * * alice's client if bob disconnected or to
+ * * bob's client if the operation completed or alice disconnected
+ * 
+ * @param client_session the associated client session
+ * @return GNUNET_NO, if we could not notify the client
+ *         GNUNET_YES if we notified it.
+ */
+static void
+prepare_client_end_notification (void * cls,
+                                 const struct GNUNET_SCHEDULER_TaskContext * 
tc)
+{
+  struct ServiceSession * session = cls;
+  struct GNUNET_VECTORPRODUCT_client_response * msg;
+  struct MessageObject * msg_obj;
+
+  GNUNET_assert (NULL != session);
+
+  msg = GNUNET_new (struct GNUNET_VECTORPRODUCT_client_response);
+  msg->header.type = htons 
(GNUNET_MESSAGE_TYPE_VECTORPRODUCT_SERVICE_TO_CLIENT);
+  memcpy (&msg->key, &session->key, sizeof (struct GNUNET_HashCode));
+  memcpy (&msg->peer, &session->peer, sizeof ( struct GNUNET_PeerIdentity));
+  msg->header.size = htons (sizeof (struct 
GNUNET_VECTORPRODUCT_client_response));
+  // 0 size and the first char in the product is 0, which should never be zero 
if encoding is used.
+  msg->product_length = htonl (0);
+
+  msg_obj = GNUNET_malloc (sizeof (struct MessageObject));
+  msg_obj->msg = (struct GNUNET_MessageHeader *) msg;
+  msg_obj->transmit_handle = NULL; // do not reset the transmit handle, please
+
+  //transmit this message to our client
+  session->client_transmit_handle =
+          GNUNET_SERVER_notify_transmit_ready (session->client,
+                                               sizeof (struct 
GNUNET_VECTORPRODUCT_client_response),
+                                               GNUNET_TIME_UNIT_FOREVER_REL,
+                                               &do_send_message,
+                                               msg_obj);
+
+
+  // if we could not even queue our request, something is wrong
+  if ( ! session->client_transmit_handle)
+    {
+
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not send message to 
client (%p)! This is OK if it was disconnected beforehand already.\n"), 
session->client);
+      // usually gets freed by do_send_message
+      GNUNET_free (msg_obj);
+      GNUNET_free (msg);
+    }
+  else
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Sending session-end notification 
to client (%p) for session %s\n"), &session->client, GNUNET_h2s 
(&session->key));
+  
+  free_session(session);
+}
+
+
+/**
+ * Bob executes:
+ * generates the response message to be sent to alice after computing 
+ * the values (1), (2), S and S'
+ *  (1)[]: $E_A(a_{\pi(i)}) \otimes E_A(- r_{\pi(i)} - b_{\pi(i)}) &= 
E_A(a_{\pi(i)} - r_{\pi(i)} - b_{\pi(i)})$
+ *  (2)[]: $E_A(a_{\pi'(i)}) \otimes E_A(- r_{\pi'(i)}) &= E_A(a_{\pi'(i)} - 
r_{\pi'(i)})$
+ *      S: $S := E_A(\sum (r_i + b_i)^2)$
+ *     S': $S' := E_A(\sum r_i^2)$
+ * 
+ * @param kp    (1)[]: $E_A(a_{\pi(i)}) \otimes E_A(- r_{\pi(i)} - b_{\pi(i)}) 
&= E_A(a_{\pi(i)} - r_{\pi(i)} - b_{\pi(i)})$
+ * @param kq    (2)[]: $E_A(a_{\pi'(i)}) \otimes E_A(- r_{\pi'(i)}) &= 
E_A(a_{\pi'(i)} - r_{\pi'(i)})$
+ * @param s         S: $S := E_A(\sum (r_i + b_i)^2)$
+ * @param stick    S': $S' := E_A(\sum r_i^2)$
+ * @param request  the associated requesting session with alice
+ * @param response the associated responder session with bob's client
+ * @return GNUNET_SYSERR if the function was called with NULL parameters or if 
there was an error
+ *         GNUNET_NO if we could not send our message
+ *         GNUNET_OK if the operation succeeded
+ */
+static int
+prepare_service_response (gcry_mpi_t * kp,
+                          gcry_mpi_t * kq,
+                          gcry_mpi_t s,
+                          gcry_mpi_t stick,
+                          struct ServiceSession * request,
+                          struct ServiceSession * response)
+{
+  struct GNUNET_VECTORPRODUCT_service_response * msg;
+  uint16_t msg_length = 0;
+  unsigned char * current = NULL;
+  unsigned char * element_exported = NULL;
+  size_t element_length = 0;
+  int i;
+
+  GNUNET_assert (request);
+
+  msg_length = sizeof (struct GNUNET_VECTORPRODUCT_service_response)
+          + 2 * request->used_element_count * PAILLIER_ELEMENT_LENGTH // kp, kq
+          + 2 * PAILLIER_ELEMENT_LENGTH; // s, stick
+
+  msg = GNUNET_malloc (msg_length);
+  GNUNET_assert (msg);
+
+  msg->header.type = htons (GNUNET_MESSAGE_TYPE_VECTORPRODUCT_BOB_TO_ALICE);
+  msg->header.size = htons (msg_length);
+  msg->element_count = htons (request->element_count);
+  msg->used_element_count = htons (request->used_element_count);
+  memcpy (&msg->key, &request->key, sizeof (struct GNUNET_HashCode));
+  current = (unsigned char *) &msg[1];
+
+  // 4 times the same logics with slight variations.
+  // doesn't really justify having 2 functions for that
+  // so i put it into blocks to enhance readability 
+  // convert s
+  {
+    element_exported = GNUNET_malloc (PAILLIER_ELEMENT_LENGTH);
+    GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG,
+                                        element_exported, 
PAILLIER_ELEMENT_LENGTH,
+                                        &element_length,
+                                        s));
+    adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH);
+    memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH);
+    GNUNET_free (element_exported);
+    current += PAILLIER_ELEMENT_LENGTH;
+  }
+
+  // convert stick
+  {
+    element_exported = GNUNET_malloc (PAILLIER_ELEMENT_LENGTH);
+    GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG,
+                                        element_exported, 
PAILLIER_ELEMENT_LENGTH,
+                                        &element_length,
+                                        stick));
+    adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH);
+    memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH);
+    GNUNET_free (element_exported);
+    current += PAILLIER_ELEMENT_LENGTH;
+  }
+
+  // convert kp[]
+  for (i = 0; i < request->used_element_count; i++)
+    {
+      element_exported = GNUNET_malloc (PAILLIER_ELEMENT_LENGTH);
+      GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG,
+                                          element_exported, 
PAILLIER_ELEMENT_LENGTH,
+                                          &element_length,
+                                          kp[i]));
+      adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH);
+      memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH);
+      GNUNET_free (element_exported);
+      current += PAILLIER_ELEMENT_LENGTH;
+    }
+
+
+  // convert kq[]
+  for (i = 0; i < request->used_element_count; i++)
+    {
+      element_exported = GNUNET_malloc (PAILLIER_ELEMENT_LENGTH);
+      GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG,
+                                          element_exported, 
PAILLIER_ELEMENT_LENGTH,
+                                          &element_length,
+                                          kq[i]));
+      adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH);
+      memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH);
+      GNUNET_free (element_exported);
+      current += PAILLIER_ELEMENT_LENGTH;
+    }
+
+  if (GNUNET_SERVER_MAX_MESSAGE_SIZE >= msg_length)
+    {
+      struct MessageObject * msg_obj;
+
+      msg_obj = GNUNET_new (struct MessageObject);
+      msg_obj->msg = (struct GNUNET_MessageHeader *) msg;
+      msg_obj->transmit_handle = (void *) &request->service_transmit_handle; 
//and reset the transmit handle
+      request->service_transmit_handle =
+              GNUNET_MESH_notify_transmit_ready (request->tunnel,
+                                                 GNUNET_YES,
+                                                 GNUNET_TIME_UNIT_FOREVER_REL,
+                                                 &request->peer, //must be 
specified, we are a slave/participant/non-owner
+                                                 msg_length,
+                                                 &do_send_message,
+                                                 msg_obj);
+      // we don't care if it could be send or not. either way, the session is 
over for us.
+      request->state = FINALIZED;
+      response->state = FINALIZED;
+    }
+  else
+    {
+      // TODO FEATURE: fallback to fragmentation, in case the message is too 
long
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Message too large, 
fragmentation is currently not supported!)\n"));
+    }
+
+  //disconnect our client
+  if ( ! request->service_transmit_handle)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send service-response 
message via mesh!)\n"));
+      GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, 
response);
+      GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
+                                    &prepare_client_end_notification,
+                                    response);
+      return GNUNET_NO;
+    }
+  return GNUNET_OK;
+}
+
+
+/**
+ * executed by bob: 
+ * compute the values 
+ *  (1)[]: $E_A(a_{\pi(i)}) \otimes E_A(- r_{\pi(i)} - b_{\pi(i)}) &= 
E_A(a_{\pi(i)} - r_{\pi(i)} - b_{\pi(i)})$
+ *  (2)[]: $E_A(a_{\pi'(i)}) \otimes E_A(- r_{\pi'(i)}) &= E_A(a_{\pi'(i)} - 
r_{\pi'(i)})$
+ *      S: $S := E_A(\sum (r_i + b_i)^2)$
+ *     S': $S' := E_A(\sum r_i^2)$
+ * 
+ * @param request the requesting session + bob's requesting peer
+ * @param response the responding session + bob's client handle
+ * @return GNUNET_SYSERR if the computation failed
+ *         GNUNET_OK if everything went well.
+ */
+static int
+compute_service_response (struct ServiceSession * request,
+                          struct ServiceSession * response)
+{
+  int i, j, ret = GNUNET_SYSERR;
+  unsigned int * p;
+  unsigned int * q;
+  uint16_t count;
+  gcry_mpi_t * r = NULL;
+  gcry_mpi_t * kp = NULL;
+  gcry_mpi_t * kq = NULL;
+  gcry_mpi_t * b;
+  gcry_mpi_t * ap;
+  gcry_mpi_t * aq;
+  gcry_mpi_t * bp;
+  gcry_mpi_t * bq;
+  gcry_mpi_t * rp;
+  gcry_mpi_t * rq;
+  gcry_mpi_t s = NULL;
+  gcry_mpi_t stick = NULL;
+  gcry_mpi_t remote_n = NULL;
+  gcry_mpi_t remote_nsquare;
+  gcry_mpi_t remote_g = NULL;
+  gcry_sexp_t tmp_exp;
+  uint32_t value;
+
+  GNUNET_assert (request != NULL && response != NULL);
+  count = request->used_element_count;
+
+  b = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
+  ap = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
+  bp = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
+  aq = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
+  bq = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
+  rp = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
+  rq = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
+
+  // convert responder session to from long to mpi
+  for (i = 0, j = 0; i < response->element_count && j < count; i++)
+    {
+      if (request->mask[i / 8] & (1 << (i % 8)))
+        {
+          value = response->vector[i] >= 0 ? response->vector[i] : 
-response->vector[i];
+          // long to gcry_mpi_t
+          if (0 > response->vector[i])
+            {
+              b[j] = gcry_mpi_new (0);
+              gcry_mpi_sub_ui (b[j], b[j], value);
+            }
+          else
+            {
+              b[j] = gcry_mpi_set_ui (NULL, value);
+            }
+          j++;
+        }
+    }
+  GNUNET_free (response->vector);
+  response->vector = NULL;
+
+  tmp_exp = gcry_sexp_find_token (request->remote_pubkey, "n", 0);
+  if ( ! tmp_exp)
+    {
+      GNUNET_break_op (0);
+      gcry_sexp_release (request->remote_pubkey);
+      request->remote_pubkey = NULL;
+      goto except;
+    }
+  remote_n = gcry_sexp_nth_mpi (tmp_exp, 1, GCRYMPI_FMT_USG);
+  if ( ! remote_n)
+    {
+      GNUNET_break (0);
+      gcry_sexp_release (tmp_exp);
+      goto except;
+    }
+  remote_nsquare = gcry_mpi_new (KEYBITS + 1);
+  gcry_mpi_mul (remote_nsquare, remote_n, remote_n);
+  gcry_sexp_release (tmp_exp);
+  tmp_exp = gcry_sexp_find_token (request->remote_pubkey, "g", 0);
+  gcry_sexp_release (request->remote_pubkey);
+  request->remote_pubkey = NULL;
+  if ( ! tmp_exp)
+    {
+      GNUNET_break_op (0);
+      gcry_mpi_release (remote_n);
+      goto except;
+    }
+  remote_g = gcry_sexp_nth_mpi (tmp_exp, 1, GCRYMPI_FMT_USG);
+  if ( ! remote_g)
+    {
+      GNUNET_break (0);
+      gcry_mpi_release (remote_n);
+      gcry_sexp_release (tmp_exp);
+      goto except;
+    }
+  gcry_sexp_release (tmp_exp);
+
+  // generate r, p and q
+  r = generate_random_vector (count);
+  p = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, count);
+  q = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, count);
+  //initialize the result vectors
+  kp = initialize_mpi_vector (count);
+  kq = initialize_mpi_vector (count);
+
+  // copy the REFERNCES of a, b and r into aq and bq. we will not change 
+  // those values, thus we can work with the references
+  memcpy (ap, request->a, sizeof (gcry_mpi_t) * count);
+  memcpy (aq, request->a, sizeof (gcry_mpi_t) * count);
+  memcpy (bp, b, sizeof (gcry_mpi_t) * count);
+  memcpy (bq, b, sizeof (gcry_mpi_t) * count);
+  memcpy (rp, r, sizeof (gcry_mpi_t) * count);
+  memcpy (rq, r, sizeof (gcry_mpi_t) * count);
+
+  // generate p and q permutations for a, b and r
+  GNUNET_assert (permute_vector (ap, p, count));
+  GNUNET_assert (permute_vector (bp, p, count));
+  GNUNET_assert (permute_vector (rp, p, count));
+  GNUNET_assert (permute_vector (aq, q, count));
+  GNUNET_assert (permute_vector (bq, q, count));
+  GNUNET_assert (permute_vector (rq, q, count));
+
+  // encrypt the element
+  // for the sake of readability I decided to have dedicated permutation
+  // vectors, which get rid of all the lookups in p/q. 
+  // however, ap/aq are not absolutely necessary but are just abstraction
+  // Calculate Kp = E(a_pi) + E(-r_pi - b_pi)
+  for (i = 0; i < count; i++)
+    {
+      // E(-r_pi - b_pi)
+      gcry_mpi_sub (kp[i], kp[i], rp[i]);
+      gcry_mpi_sub (kp[i], kp[i], bp[i]);
+      encrypt_element (kp[i], kp[i], NULL, remote_g, remote_n, remote_nsquare);
+
+      // E(-r_pi - b_pi) * E(a_pi) ==  E(a + (-r -b))
+      //gcry_mpi_mulm (kp[i], kp[i], ap[i], remote_nsquare);
+      gcry_mpi_add (kp[i], kp[i], ap[i]);
+    }
+  GNUNET_free (ap);
+  GNUNET_free (bp);
+  GNUNET_free (rp);
+
+  // Calculate Kq = E(a_qi) + E( -r_qi)
+  for (i = 0; i < count; i++)
+    {
+      // E(-r_qi)
+      gcry_mpi_sub (kq[i], kq[i], rq[i]);
+      encrypt_element (kq[i], kq[i], NULL, remote_g, remote_n, remote_nsquare);
+
+      // E(-r_qi) * E(a_qi) == E(aqi + (- rqi))
+      //gcry_mpi_mulm (kq[i], kq[i], aq[i], remote_nsquare);
+      gcry_mpi_add (kq[i], kq[i], aq[i]);
+    }
+  GNUNET_free (aq);
+  GNUNET_free (bq);
+  GNUNET_free (rq);
+
+  // Calculate S' =  E(SUM( r_i^2 ))
+  stick = compute_square_sum (r, count);
+  encrypt_element (stick, stick, NULL, remote_g, remote_n, remote_nsquare);
+
+  // Calculate S = E(SUM( (r_i + b_i)^2 ))
+  for (i = 0; i < count; i++)
+    {
+      gcry_mpi_add (r[i], r[i], b[i]);
+    }
+  s = compute_square_sum (r, count);
+  encrypt_element (s, s, NULL, remote_g, remote_n, remote_nsquare);
+  gcry_mpi_release (remote_n);
+  gcry_mpi_release (remote_g);
+  gcry_mpi_release (remote_nsquare);
+
+  // release r and tmp
+  for (i = 0; i < count; i++)
+    // rp, rq, aq, ap, bp, bq are released along with a, r, b respectively, (a 
and b are handled at except:)
+    gcry_mpi_release (r[i]);
+
+  // copy the Kp[], Kq[], S and Stick into a new message
+  if (GNUNET_YES != prepare_service_response (kp, kq, s, stick, request, 
response))
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Computation of values for alice 
failed!\n"));
+  else
+    ret = GNUNET_OK;
+
+  for (i = 0; i < count; i++)
+    {
+      gcry_mpi_release (kq[i]);
+      gcry_mpi_release (kp[i]);
+    }
+
+  gcry_mpi_release (s);
+  gcry_mpi_release (stick);
+
+except:
+  for (i = 0; i < count; i++)
+    {
+      gcry_mpi_release (b[i]);
+      gcry_mpi_release (request->a[i]);
+    }
+
+  GNUNET_free (b);
+  GNUNET_free (request->a);
+  request->a = NULL;
+
+  return ret;
+}
+
+
+/**
+ * Executed by Alice, fills in a service-request message and sends it to the 
given peer
+ * 
+ * @param session the session associated with this request, then also holds 
the CORE-handle
+ * @return GNUNET_SYSERR if we could not send the message
+ *         GNUNET_NO if the message was too large
+ *         GNUNET_OK if we sent it
+ */
+static void
+prepare_service_request (void *cls,
+                         const struct GNUNET_PeerIdentity * peer,
+                         const struct GNUNET_ATS_Information * atsi)
+{
+  struct ServiceSession * session = cls;
+  unsigned char * current;
+  struct GNUNET_VECTORPRODUCT_service_request * msg;
+  struct MessageObject * msg_obj;
+  unsigned int i;
+  unsigned int j;
+  uint16_t msg_length;
+  size_t element_length = 0; //gets initialized by gcry_mpi_print, but the 
compiler doesn't know that
+  gcry_mpi_t a;
+  gcry_mpi_t r;
+  uint32_t value;
+
+  GNUNET_assert (NULL != cls);
+  GNUNET_assert (NULL != peer);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Successfully created new tunnel to 
peer (%s)!\n"), GNUNET_i2s (peer));
+
+  msg_length = sizeof (struct GNUNET_VECTORPRODUCT_service_request)
+          + session->used_element_count * PAILLIER_ELEMENT_LENGTH
+          + session->mask_length
+          + my_pubkey_external_length;
+
+  if (GNUNET_SERVER_MAX_MESSAGE_SIZE < sizeof (struct 
GNUNET_VECTORPRODUCT_service_request)
+      + session->used_element_count * PAILLIER_ELEMENT_LENGTH
+      + session->mask_length
+      + my_pubkey_external_length)
+    {
+      // TODO FEATURE: fallback to fragmentation, in case the message is too 
long
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Message too large, 
fragmentation is currently not supported!\n"));
+      GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, 
session);
+      GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
+                                    &prepare_client_end_notification,
+                                    session);
+      return;
+    }
+  msg = GNUNET_malloc (msg_length);
+
+  msg->header.type = htons (GNUNET_MESSAGE_TYPE_VECTORPRODUCT_ALICE_TO_BOB);
+  memcpy (&msg->key, &session->key, sizeof (struct GNUNET_HashCode));
+  msg->mask_length = htons (session->mask_length);
+  msg->pk_length = htons (my_pubkey_external_length);
+  msg->used_element_count = htons (session->used_element_count);
+  msg->element_count = htons (session->element_count);
+  msg->header.size = htons (msg_length);
+
+  // fill in the payload
+  current = (unsigned char *) &msg[1];
+  // copy over the mask
+  memcpy (current, session->mask, session->mask_length);
+  // copy over our public key
+  current += session->mask_length;
+  memcpy (current, my_pubkey_external, my_pubkey_external_length);
+  current += my_pubkey_external_length;
+  
+  // now copy over the element vector
+  session->a = GNUNET_malloc (sizeof (gcry_mpi_t) * 
session->used_element_count);
+  a = gcry_mpi_new (KEYBITS * 2);
+  r = gcry_mpi_new (KEYBITS * 2);
+  // encrypt our vector and generate string representations
+  for (i = 0, j = 0; i < session->element_count; i++)
+    {
+      // if this is a used element...
+      if (session->mask[i / 8] & 1 << (i % 8))
+        {
+          unsigned char * element_exported = GNUNET_malloc 
(PAILLIER_ELEMENT_LENGTH);
+          value = session->vector[i] >= 0 ? session->vector[i] : 
-session->vector[i];
+
+          // long to gcry_mpi_t
+          if (session->vector[i] < 0)
+            {
+              a = gcry_mpi_set_ui (NULL, 0);
+              gcry_mpi_sub_ui (a, a, value);
+            }
+          else
+            a = gcry_mpi_set_ui (NULL, value);
+
+          // multiply with a given factor to avoid disclosing 1
+          session->a[j++] = gcry_mpi_set (NULL, a);
+          encrypt_element (a, a, r, my_g, my_n, my_nsquare);
+
+          // get representation as string
+          // we always supply some value, so gcry_mpi_print fails only if it 
can't reserve memory
+          GNUNET_assert ( ! gcry_mpi_print (GCRYMPI_FMT_USG,
+                                              element_exported, 
PAILLIER_ELEMENT_LENGTH,
+                                              &element_length,
+                                              a));
+
+          // move buffer content to the end of the buffer so it can easily be 
read by libgcrypt. also this now has fixed size
+          adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH);
+
+          // copy over to the message
+          memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH);
+          current += PAILLIER_ELEMENT_LENGTH;
+        }
+    }
+  gcry_mpi_release (a);
+  gcry_mpi_release (r);
+
+  msg_obj = GNUNET_malloc (sizeof (struct MessageObject));
+  msg_obj->msg = (struct GNUNET_MessageHeader *) msg;
+  msg_obj->transmit_handle = (void *) &session->service_transmit_handle; //and 
reset the transmit handle
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transmitting service request.\n"));
+
+  //transmit via mesh messaging
+  session->state = WAITING_FOR_RESPONSE_FROM_SERVICE;
+  session->service_transmit_handle = GNUNET_MESH_notify_transmit_ready 
(session->tunnel, GNUNET_YES,
+                                                                        
GNUNET_TIME_UNIT_FOREVER_REL,
+                                                                        peer, 
//multicast to all targets, maybe useful in the future
+                                                                        
msg_length,
+                                                                        
&do_send_message,
+                                                                        
msg_obj);
+  if ( ! session->service_transmit_handle)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not send mutlicast message 
to tunnel!\n"));
+      GNUNET_free (msg_obj);
+      GNUNET_free (msg);
+      GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, 
session);
+      GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
+                                    &prepare_client_end_notification,
+                                    session);
+      return;
+    }
+}
+
+
+/**
+ * Method called whenever a peer has disconnected from the tunnel.
+ * Implementations of this callback must NOT call
+ * GNUNET_MESH_tunnel_destroy immediately, but instead schedule those
+ * to run in some other task later.  However, calling 
+ * "GNUNET_MESH_notify_transmit_ready_cancel" is allowed.
+ *
+ * @param cls closure
+ * @param peer peer identity the tunnel stopped working with
+ */
+static void
+tunnel_peer_disconnect_handler (void *cls, const struct GNUNET_PeerIdentity * 
peer)
+{
+  // as we have only one peer connected in each session, just remove the 
session and say good bye
+  struct ServiceSession * session = cls;
+  struct ServiceSession * curr;
+  GNUNET_assert(cls);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Peer (%s) disconnected from our 
tunnel!\n"), GNUNET_i2s (peer));
+
+  if ((session->role == ALICE) && (FINALIZED != session->state) && ( ! 
do_shutdown))
+    {
+      for (curr = from_client_head; NULL != curr; curr = curr->next)
+        if (curr == session)
+          {
+            GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, 
session);
+            break;
+          }
+      GNUNET_SCHEDULER_add_now (&destroy_tunnel,
+                                session);
+      // if this happened before we received the answer, we must terminate the 
session
+      GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
+                                    &prepare_client_end_notification,
+                                    session);
+    }
+}
+
+
+/**
+ * Handler for a client request message. 
+ * Can either be type A or B
+ *   A: request-initiation to compute a scalar product with a peer
+ *   B: response role, keep the values + session and wait for a matching 
session or process a waiting request   
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_client_request (void *cls,
+                       struct GNUNET_SERVER_Client *client,
+                       const struct GNUNET_MessageHeader *message)
+{
+  struct GNUNET_VECTORPRODUCT_client_request * msg = (struct 
GNUNET_VECTORPRODUCT_client_request *) message;
+  struct ServiceSession * session;
+  uint16_t element_count;
+  uint16_t mask_length;
+  uint16_t msg_type;
+  int32_t * vector;
+  uint32_t i;
+
+  GNUNET_assert (message);
+
+  //we need at least a peer and one message id to compare
+  if (sizeof (struct GNUNET_VECTORPRODUCT_client_request) > ntohs 
(msg->header.size))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Too short message received 
from client!\n"));
+      GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+      return;
+    }
+
+  msg_type = ntohs (msg->header.type);
+  element_count = ntohs (msg->element_count);
+  mask_length = ntohs (msg->mask_length);
+
+  //sanity check: is the message as long as the message_count fields suggests?
+  if (( ntohs (msg->header.size) != (sizeof (struct 
GNUNET_VECTORPRODUCT_client_request) + element_count * sizeof (int32_t) + 
mask_length))
+      || (0 == element_count))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Invalid message received from 
client, session information incorrect!\n"));
+      GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+      return;
+    }
+
+  // do we have a duplicate session here already?
+  if (NULL != find_matching_session (from_client_tail,
+                                     &msg->key,
+                                     element_count,
+                                     NULL, NULL))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Duplicate session information 
received, cannot create new session with key `%s'\n"), GNUNET_h2s (&msg->key));
+      GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+      return;
+    }
+
+  session = GNUNET_malloc (sizeof (struct ServiceSession));
+  session->client = client;
+  session->element_count = element_count;
+  session->mask_length = mask_length;
+  // get our transaction key
+  memcpy (&session->key, &msg->key, sizeof (struct GNUNET_HashCode));
+  //allocate memory for vector and encrypted vector
+  session->vector = GNUNET_malloc (sizeof (int32_t) * element_count);
+  vector = (int32_t *) & msg[1];
+
+  if (GNUNET_MESSAGE_TYPE_VECTORPRODUCT_CLIENT_TO_ALICE == msg_type)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Got client-request-session with 
key %s, preparing tunnel to remote service.\n"), GNUNET_h2s (&session->key));
+
+      session->role = ALICE;
+      // fill in the mask
+      session->mask = GNUNET_malloc (mask_length);
+      memcpy (session->mask, &vector[element_count], mask_length);
+
+      // copy over the elements
+      session->used_element_count = 0;
+      for (i = 0; i < element_count; i++)
+        {
+          session->vector[i] = ntohl (vector[i]);
+          if (session->vector[i] == 0)
+            session->mask[i / 8] &= ~(1 << (i % 8));
+          if (session->mask[i / 8] & (1 << (i % 8)))
+            session->used_element_count++;
+        }
+
+      if ( ! session->used_element_count)
+        {
+          GNUNET_break_op (0);
+          GNUNET_free (session->vector);
+          GNUNET_free (session->a);
+          GNUNET_free (session);
+          GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+          return;
+        }
+      //session with ourself makes no sense!
+      if ( ! memcmp (&msg->peer, &me, sizeof (struct GNUNET_PeerIdentity)))
+        {
+          GNUNET_break (0);
+          GNUNET_free (session->vector);
+          GNUNET_free (session->a);
+          GNUNET_free (session);
+          GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+          return;
+        }
+      // get our peer ID
+      memcpy (&session->peer, &msg->peer, sizeof (struct GNUNET_PeerIdentity));
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Creating new tunnel to for 
session with key %s.\n"), GNUNET_h2s (&session->key));
+      GNUNET_CONTAINER_DLL_insert (from_client_head, from_client_tail, 
session);
+      session->tunnel = GNUNET_MESH_tunnel_create (my_mesh, session,
+                                                   prepare_service_request,
+                                                   
tunnel_peer_disconnect_handler,
+                                                   session);
+      if ( ! session->tunnel)
+        {
+          GNUNET_break (0);
+          GNUNET_free (session->vector);
+          GNUNET_free (session->a);
+          GNUNET_free (session);
+          GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+          return;
+        }
+      GNUNET_MESH_peer_request_connect_add (session->tunnel, &session->peer);
+      GNUNET_SERVER_receive_done (client, GNUNET_YES);
+      session->state = WAITING_FOR_BOBS_CONNECT;
+    }
+  else
+    {
+      struct ServiceSession * requesting_session;
+      enum SessionState needed_state = REQUEST_FROM_SERVICE_RECEIVED;
+
+      session->role = BOB;
+      session->mask = NULL;
+      // copy over the elements
+      session->used_element_count = element_count;
+      for (i = 0; i < element_count; i++)
+        session->vector[i] = ntohl (vector[i]);
+      session->state = MESSAGE_FROM_RESPONDING_CLIENT_RECEIVED;
+      
+      GNUNET_CONTAINER_DLL_insert (from_client_head, from_client_tail, 
session);
+      GNUNET_SERVER_receive_done (client, GNUNET_YES);
+      //check if service queue contains a matching request 
+      requesting_session = find_matching_session (from_service_tail,
+                                                  &session->key,
+                                                  session->element_count,
+                                                  &needed_state, NULL);
+      if (NULL != requesting_session)
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got client-responder-session 
with key %s and a matching service-request-session set, processing.\n"), 
GNUNET_h2s (&session->key));
+          if (GNUNET_OK != compute_service_response (requesting_session, 
session))
+            {
+              GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, 
session);
+              GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
+                                            &prepare_client_end_notification,
+                                            session);
+            }
+        }
+      else
+        GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got client-responder-session 
with key %s but NO matching service-request-session set, queuing element for 
later use.\n"), GNUNET_h2s (&session->key));
+        // no matching session exists yet, store the response
+        // for later processing by handle_service_request()
+    }
+}
+
+
+/**
+ * Function called for inbound tunnels. 
+ *
+ * @param cls closure
+ * @param tunnel new handle to the tunnel
+ * @param initiator peer that started the tunnel
+ * @param atsi performance information for the tunnel
+ * @return initial tunnel context for the tunnel
+ *         (can be NULL -- that's not an error)
+ */
+static void *
+tunnel_incoming_handler (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
+                         const struct GNUNET_PeerIdentity *initiator,
+                         const struct GNUNET_ATS_Information *atsi)
+{
+
+  struct ServiceSession * c = GNUNET_new (struct ServiceSession);
+
+  memcpy (&c->peer, initiator, sizeof (struct GNUNET_PeerIdentity));
+  c->tunnel = tunnel;
+  c->role = BOB;
+  return c;
+}
+
+
+/**
+ * Function called whenever an inbound tunnel is destroyed.  Should clean up
+ * any associated state.
+ *
+ * @param cls closure (set from GNUNET_MESH_connect)
+ * @param tunnel connection to the other end (henceforth invalid)
+ * @param tunnel_ctx place where local state associated
+ *                   with the tunnel is stored (our 'struct TunnelState')
+ */
+static void
+tunnel_destruction_handler (void *cls,
+                            const struct GNUNET_MESH_Tunnel *tunnel,
+                            void *tunnel_ctx)
+{
+  struct ServiceSession * service_session = tunnel_ctx;
+  struct ServiceSession * client_session;
+  struct ServiceSession * curr;
+
+  GNUNET_assert (service_session);
+  if (!memcmp (&service_session->peer, &me, sizeof (struct 
GNUNET_PeerIdentity)))
+    return;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Tunnel destroyed, terminating 
session with peer (%s)\n"), GNUNET_i2s (&service_session->peer));
+  // remove the session, unless it has already been dequeued, but somehow 
still active
+  // this could bug without the IF in case the queue is empty and the service 
session was the only one know to the service
+  for (curr = from_service_head; NULL != curr; curr = curr->next)
+        if (curr == service_session)
+          {
+            GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, 
curr);
+            break;
+          }
+  // there is a client waiting for this service session, terminate it, too!
+  // i assume the tupel of key and element count is unique. if it was not the 
rest of the code would not work either.
+  client_session = find_matching_session (from_client_tail,
+                                          &service_session->key,
+                                          service_session->element_count,
+                                          NULL, NULL);
+  free_session (service_session);
+
+  // the client has to check if it was waiting for a result 
+  // or if it was a responder, no point in adding more statefulness
+  if (client_session && ( ! do_shutdown))
+    {
+      // remove the session, we just found it in the queue, so it must be there
+      GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, 
client_session);
+      GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
+                                    &prepare_client_end_notification,
+                                    client_session);
+    }
+}
+
+
+/**
+ * Compute our scalar product, done by Alice
+ * 
+ * @param session - the session associated with this computation
+ * @param kp - (1) from the protocol definition: 
+ *             $E_A(a_{\pi(i)}) \otimes E_A(- r_{\pi(i)} - b_{\pi(i)}) &= 
E_A(a_{\pi(i)} - r_{\pi(i)} - b_{\pi(i)})$
+ * @param kq - (2) from the protocol definition: 
+ *             $E_A(a_{\pi'(i)}) \otimes E_A(- r_{\pi'(i)}) &= E_A(a_{\pi'(i)} 
- r_{\pi'(i)})$
+ * @param s - S from the protocol definition: 
+ *            $S := E_A(\sum (r_i + b_i)^2)$
+ * @param stick - S' from the protocol definition: 
+ *                $S' := E_A(\sum r_i^2)$
+ * @return product as MPI, never NULL
+ */
+static gcry_mpi_t
+compute_scalar_product (struct ServiceSession * session,
+                        gcry_mpi_t * kp, gcry_mpi_t * kq, gcry_mpi_t s, 
gcry_mpi_t stick)
+{
+  uint16_t count;
+  gcry_mpi_t divider;
+  gcry_mpi_t t;
+  gcry_mpi_t u;
+  gcry_mpi_t utick;
+  gcry_mpi_t p;
+  gcry_mpi_t ptick;
+  gcry_mpi_t product;
+  gcry_mpi_t tmp;
+  unsigned int i;
+
+  count = session->used_element_count;
+  tmp = gcry_mpi_new (KEYBITS);
+  for (i = 0; i < count; i++)
+    {
+      decrypt_element (kp[i], kp[i], my_mu, my_lambda, my_n, my_nsquare);
+      decrypt_element (kq[i], kq[i], my_mu, my_lambda, my_n, my_nsquare);
+    }
+
+  // calculate t = E(sum(ai))
+  t = compute_square_sum (session->a, count);
+  encrypt_element (t, t, NULL, my_g, my_n, my_nsquare);
+
+  // calculate U
+  u = gcry_mpi_new (0);
+  tmp = compute_square_sum (kp, count);
+  gcry_mpi_sub (u, u, tmp);
+  encrypt_element (u, u, NULL, my_g, my_n, my_nsquare);
+  gcry_mpi_release (tmp);
+
+  //calculate U'
+  utick = gcry_mpi_new (0);
+  tmp = compute_square_sum (kq, count);
+  gcry_mpi_sub (utick, utick, tmp);
+  encrypt_element (utick, utick, NULL, my_g, my_n, my_nsquare);
+  gcry_mpi_release (tmp);
+
+  GNUNET_assert (p = gcry_mpi_new (0));
+  GNUNET_assert (ptick = gcry_mpi_new (0));
+
+  // compute P
+  gcry_mpi_add (p, s, t);
+  //gcry_mpi_mulm (p, p, u, my_nsquare);
+  gcry_mpi_add (p, p, u);
+  decrypt_element (p, p, my_mu, my_lambda, my_n, my_nsquare);
+
+  // compute P'
+  gcry_mpi_add (ptick, stick, t);
+  //gcry_mpi_mulm (ptick, ptick, utick, my_nsquare);
+  gcry_mpi_add (ptick, ptick, utick);
+  decrypt_element (ptick, ptick, my_mu, my_lambda, my_n, my_nsquare);
+
+  gcry_mpi_release (t);
+  gcry_mpi_release (u);
+  gcry_mpi_release (utick);
+
+  // compute product
+  GNUNET_assert (product = gcry_mpi_new (0));
+  gcry_mpi_sub (product, p, ptick);
+  gcry_mpi_release (p);
+  gcry_mpi_release (ptick);
+  divider = gcry_mpi_set_ui (NULL, 2);
+  gcry_mpi_div (product, NULL, product, divider, 0);
+
+  gcry_mpi_release (divider);
+  for (i = 0; i < count; i++)
+    gcry_mpi_release (session->a[i]);
+  GNUNET_free (session->a);
+  session->a = NULL;
+  
+  return product;
+}
+
+
+/**
+ * prepare the response we will send to alice or bobs' clients.
+ * in Bobs case the product will be NULL. 
+ * 
+ * @param session  the session associated with our client.
+ */
+static void
+prepare_client_response (void *cls,
+                         const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct ServiceSession * session = cls;
+  struct GNUNET_VECTORPRODUCT_client_response * msg;
+  unsigned char * product_exported = NULL;
+  size_t product_length = 0;
+  uint16_t msg_length = 0;
+  struct MessageObject * msg_obj;
+
+  GNUNET_assert (session);
+  
+  if (session->product)
+    {
+      // get representation as string
+      GNUNET_assert ( ! gcry_mpi_aprint (GCRYMPI_FMT_USG,
+                                           &product_exported,
+                                           &product_length,
+                                           session->product));
+      gcry_mpi_release (session->product);
+      session->product = NULL;
+    }
+
+  msg_length = sizeof (struct GNUNET_VECTORPRODUCT_client_response) 
+product_length;
+  msg = GNUNET_malloc (msg_length);
+  memcpy (&msg[1], product_exported, product_length);
+  GNUNET_free_non_null (product_exported);
+  msg->header.type = htons 
(GNUNET_MESSAGE_TYPE_VECTORPRODUCT_SERVICE_TO_CLIENT);
+  msg->header.size = htons (msg_length);
+  memcpy (&msg->key, &session->key, sizeof (struct GNUNET_HashCode));
+  memcpy (&msg->peer, &session->peer, sizeof ( struct GNUNET_PeerIdentity));
+  msg->product_length = htonl (product_length);
+  
+  msg_obj = GNUNET_malloc (sizeof (struct MessageObject));
+  msg_obj->msg = (struct GNUNET_MessageHeader *) msg;
+  msg_obj->transmit_handle = NULL; // don't reset the transmit handle
+
+  //transmit this message to our client
+  session->client_transmit_handle =
+          GNUNET_SERVER_notify_transmit_ready (session->client,
+                                               msg_length,
+                                               GNUNET_TIME_UNIT_FOREVER_REL,
+                                               &do_send_message,
+                                               msg_obj);
+  if ( ! session->client_transmit_handle)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not send message to 
client (%p)! This probably is OK if the client disconnected before us.\n"), 
session->client);
+      session->client = NULL;
+      // callback was not called!
+      GNUNET_free (msg_obj);
+      GNUNET_free (msg);
+    }
+  else
+      // gracefully sent message, just terminate session structure
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Sent result to client (%p), this 
session (%s) has ended!\n"), session->client, GNUNET_h2s (&session->key));
+  free_session (session);
+}
+
+
+/**
+ * Handle a request from another service to calculate a vectorproduct with us.
+ *
+ * @param cls closure (set from GNUNET_MESH_connect)
+ * @param tunnel connection to the other end
+ * @param tunnel_ctx place to store local state associated with the tunnel
+ * @param sender who sent the message
+ * @param message the actual message
+ * @param atsi performance data for the connection
+ * @return GNUNET_OK to keep the connection open,
+ *         GNUNET_SYSERR to close it (signal serious error)
+ */
+static int
+handle_service_request (void *cls,
+                        struct GNUNET_MESH_Tunnel * tunnel,
+                        void **tunnel_ctx,
+                        const struct GNUNET_PeerIdentity * sender,
+                        const struct GNUNET_MessageHeader * message,
+                        const struct GNUNET_ATS_Information * atsi)
+{
+  struct ServiceSession * session;
+  struct GNUNET_VECTORPRODUCT_service_request * msg = (struct 
GNUNET_VECTORPRODUCT_service_request *) message;
+  uint16_t mask_length;
+  uint16_t pk_length;
+  uint16_t used_elements;
+  uint16_t element_count;
+  uint16_t msg_length;
+  unsigned char * current;
+  struct ServiceSession * responder_session;
+  int32_t i = -1;
+  enum SessionState needed_state;
+
+  GNUNET_assert (NULL != message);
+  GNUNET_assert (NULL != sender);
+  GNUNET_assert (NULL != tunnel_ctx);
+  session = (struct ServiceSession *) * tunnel_ctx;
+  // is this tunnel already in use?
+  if ( (session->next) || (from_service_head == session))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Got a service request over a 
tunnel that is already in use, ignoring!\n"));
+      return GNUNET_SYSERR;
+    }
+  // Check if message was sent by me, which would be bad!
+  if ( ! memcmp (sender, &me, sizeof (struct GNUNET_PeerIdentity)))
+    {
+      GNUNET_break (0);
+      GNUNET_free (session);
+      return GNUNET_SYSERR;
+    }
+  // this protocol can at best be 1:N, but never M:N!
+  // Check if the sender is not the peer, I am connected to, which would be 
bad!
+  if (memcmp (sender, &session->peer, sizeof (struct GNUNET_PeerIdentity)))
+    {
+      GNUNET_break (0);
+      GNUNET_free (session);
+      return GNUNET_SYSERR;
+    }
+
+  //we need at least a peer and one message id to compare
+  if (ntohs (msg->header.size) < sizeof (struct 
GNUNET_VECTORPRODUCT_service_request))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Too short message received 
from peer!\n"));
+      GNUNET_free (session);
+      return GNUNET_SYSERR;
+    }
+  mask_length = ntohs (msg->mask_length);
+  pk_length = ntohs (msg->pk_length);
+  used_elements = ntohs (msg->used_element_count);
+  element_count = ntohs (msg->element_count);
+  msg_length = sizeof (struct GNUNET_VECTORPRODUCT_service_request)
+               + mask_length + pk_length + used_elements * 
PAILLIER_ELEMENT_LENGTH;
+
+  //sanity check: is the message as long as the message_count fields suggests?
+  if ((ntohs (msg->header.size) != msg_length) || (element_count < 
used_elements)
+      || (used_elements == 0) || (mask_length != (element_count / 8 + 
(element_count % 8 ? 1 : 0)))
+      )
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Invalid message received from 
peer, message count does not match message length!\n"));
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Used elements: %hu\nElement 
Count: %hu\nExpected Mask Length: %hu\nCalculated Masklength: %d\n"), 
used_elements, element_count, mask_length, (element_count / 8 + (element_count 
% 8 ? 1 : 0)));
+      GNUNET_free (session);
+      return GNUNET_SYSERR;
+    }
+  if (find_matching_session (from_service_tail,
+                             &msg->key,
+                             element_count,
+                             NULL,
+                             sender))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Got message with duplicate 
session key (`%s'), ignoring service request.\n"), (const char *) &(msg->key));
+      GNUNET_free (session);
+      return GNUNET_SYSERR;
+    }
+  
+  memcpy (&session->peer, sender, sizeof (struct GNUNET_PeerIdentity));
+  session->state = REQUEST_FROM_SERVICE_RECEIVED;
+  session->element_count = ntohs (msg->element_count);
+  session->used_element_count = used_elements;
+  session->tunnel = tunnel;
+
+  // session key
+  memcpy (&session->key, &msg->key, sizeof (struct GNUNET_HashCode));
+  current = (unsigned char *) &msg[1];
+  //preserve the mask, we will need that later on
+  session->mask = GNUNET_malloc (mask_length);
+  memcpy (session->mask, current, mask_length);
+  //the public key
+  current += mask_length;
+
+  //convert the publickey to sexp
+  if (gcry_sexp_new (&session->remote_pubkey, current, pk_length, 1))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not translate remote 
public key to sexpression!\n"));
+      GNUNET_free (session->mask);
+      GNUNET_free (session);
+      return GNUNET_SYSERR;
+    }
+
+  current += pk_length;
+
+  //check if service queue contains a matching request 
+  needed_state = MESSAGE_FROM_RESPONDING_CLIENT_RECEIVED;
+  responder_session = find_matching_session (from_client_tail,
+                                             &session->key,
+                                             session->element_count,
+                                             &needed_state, NULL);
+
+  session->a = GNUNET_malloc (sizeof (gcry_mpi_t) * used_elements);
+
+  if (GNUNET_SERVER_MAX_MESSAGE_SIZE >= sizeof (struct 
GNUNET_VECTORPRODUCT_service_request)
+      +pk_length
+      + mask_length
+      + used_elements * PAILLIER_ELEMENT_LENGTH)
+    {
+      gcry_error_t ret = 0;
+      session->a = GNUNET_malloc (sizeof (gcry_mpi_t) * used_elements);
+      // Convert each vector element to MPI_value
+      for (i = 0; i < used_elements; i++)
+        {
+          size_t read = 0;
+
+          ret = gcry_mpi_scan (&session->a[i],
+                               GCRYMPI_FMT_USG,
+                               &current[i * PAILLIER_ELEMENT_LENGTH],
+                               PAILLIER_ELEMENT_LENGTH,
+                               &read);
+          if (ret) // read < GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH
+            {
+              GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not translate 
E[a%d] to MPI!\n%s/%s\n"),
+                          i, gcry_strsource (ret), gcry_strerror (ret));
+              goto except;
+            }
+        }
+      GNUNET_CONTAINER_DLL_insert (from_service_head, from_service_tail, 
session);
+      if (responder_session)
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got session with key %s and 
a matching element set, processing.\n"), GNUNET_h2s (&session->key));
+          if (GNUNET_OK != compute_service_response (session, 
responder_session))
+            {
+              //something went wrong, remove it again...
+              GNUNET_CONTAINER_DLL_remove (from_service_head, 
from_service_tail, session);
+              goto except;
+            }
+        }
+      else
+          GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got session with key %s 
without a matching element set, queueing.\n"), GNUNET_h2s (&session->key));
+      return GNUNET_OK;
+    }
+  else
+    {
+      // TODO FEATURE: fallback to fragmentation, in case the message is too 
long
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Message too large, 
fragmentation is currently not supported!\n"));
+      goto except;
+    }
+except:
+  for (i = 0; i < used_elements; i++)
+    if (session->a[i])
+      gcry_mpi_release (session->a[i]);
+  gcry_sexp_release (session->remote_pubkey);
+  session->remote_pubkey = NULL;
+  GNUNET_free_non_null (session->a);
+  session->a = NULL;
+  free_session (session);
+  // and notify our client-session that we could not complete the session
+  if (responder_session)
+    {
+      // we just found the responder session in this queue
+      GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, 
responder_session);
+      GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
+                                    &prepare_client_end_notification,
+                                    responder_session);
+    }
+  return GNUNET_SYSERR;
+}
+
+
+/**
+ * Handle a response we got from another service we wanted to calculate a 
vectorproduct with.
+ *
+ * @param cls closure (set from GNUNET_MESH_connect)
+ * @param tunnel connection to the other end
+ * @param tunnel_ctx place to store local state associated with the tunnel
+ * @param sender who sent the message
+ * @param message the actual message
+ * @param atsi performance data for the connection
+ * @return GNUNET_OK to keep the connection open,
+ *         GNUNET_SYSERR to close it (signal serious error)
+ */
+static int
+handle_service_response (void *cls,
+                         struct GNUNET_MESH_Tunnel * tunnel,
+                         void **tunnel_ctx,
+                         const struct GNUNET_PeerIdentity * sender,
+                         const struct GNUNET_MessageHeader * message,
+                         const struct GNUNET_ATS_Information * atsi)
+{
+
+  struct ServiceSession * session;
+  struct GNUNET_VECTORPRODUCT_service_response * msg = (struct 
GNUNET_VECTORPRODUCT_service_response *) message;
+  unsigned char * current;
+  uint16_t count;
+  gcry_mpi_t s = NULL;
+  gcry_mpi_t stick = NULL;
+  size_t read;
+  size_t i;
+  uint16_t used_element_count;
+  size_t msg_size;
+  gcry_mpi_t * kp = NULL;
+  gcry_mpi_t * kq = NULL;
+
+  GNUNET_assert (NULL != message);
+  GNUNET_assert (NULL != sender);
+  GNUNET_assert (NULL != tunnel_ctx);
+  session = (struct ServiceSession *) * tunnel_ctx;
+  GNUNET_assert (NULL != session);
+  count = session->used_element_count;
+  session->product = NULL;
+
+  if (memcmp (&session->peer, sender, sizeof (struct GNUNET_PeerIdentity)))
+    {
+      GNUNET_break_op (0);
+      goto invalid_msg;
+    }
+  //we need at least a peer and one message id to compare
+  if (sizeof (struct GNUNET_VECTORPRODUCT_service_response) > ntohs 
(msg->header.size))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Too short message received 
from peer!\n"));
+      goto invalid_msg;
+    }
+  used_element_count = ntohs (msg->used_element_count);
+  msg_size = sizeof (struct GNUNET_VECTORPRODUCT_service_response)
+          + 2 * used_element_count * PAILLIER_ELEMENT_LENGTH
+          + 2 * PAILLIER_ELEMENT_LENGTH;
+  //sanity check: is the message as long as the message_count fields suggests?
+  if ((ntohs (msg->header.size) != msg_size) || (count != used_element_count))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Invalid message received from 
peer!\n"));
+      goto invalid_msg;
+    }
+  if (GNUNET_SERVER_MAX_MESSAGE_SIZE < msg_size)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Message too large, 
fragmentation is currently not supported!\n"));
+      goto invalid_msg;
+    }
+
+  //convert s
+  current = (unsigned char *) &msg[1];
+  if (gcry_mpi_scan (&s, GCRYMPI_FMT_USG, current, 
+                     PAILLIER_ELEMENT_LENGTH, &read))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not translate s to an 
MPI value!\n"));
+      goto invalid_msg;
+    }
+  current += PAILLIER_ELEMENT_LENGTH;
+  //convert stick
+  if (gcry_mpi_scan (&stick, GCRYMPI_FMT_USG, current,
+                       PAILLIER_ELEMENT_LENGTH, &read))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not translate s' to an 
MPI value!\n"));
+      goto invalid_msg;
+    }
+  current += PAILLIER_ELEMENT_LENGTH;
+
+  kp = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
+  // Convert each kp[] to its MPI_value
+  for (i = 0; i < count; i++)
+    {
+      if (gcry_mpi_scan (&kp[i], GCRYMPI_FMT_USG, current,
+                           PAILLIER_ELEMENT_LENGTH, &read))
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not translate 
Kp[%d]to an MPI value!\n"), i);
+          goto invalid_msg;
+        }
+      current += PAILLIER_ELEMENT_LENGTH;
+    }
+
+
+  kq = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
+  // Convert each kq[] to its MPI_value
+  for (i = 0; i < count; i++)
+    {
+      if (gcry_mpi_scan (&kq[i], GCRYMPI_FMT_USG, current,
+                           PAILLIER_ELEMENT_LENGTH, &read))
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not translate 
Kq[%d]to an MPI value!\n"), i);
+          goto invalid_msg;
+        }
+      current += PAILLIER_ELEMENT_LENGTH;
+    }
+  
+  session->product = compute_scalar_product (session, kp, kq, s, stick);
+  
+invalid_msg:
+  if (s)
+    gcry_mpi_release (s);
+  if (stick)
+    gcry_mpi_release (stick);
+  for (i = 0; kp && i < count; i++)
+    if (kp[i]) gcry_mpi_release (kp[i]);
+  for (i = 0; kq && i < count; i++)
+    if (kq[i]) gcry_mpi_release (kq[i]);
+  GNUNET_free_non_null (kp);
+  GNUNET_free_non_null (kq);
+  
+  session->state = FINALIZED;
+  // the tunnel has done its job, terminate our connection and the tunnel
+  // the peer will be notified that the tunnel was destroyed via 
tunnel_destruction_handler
+  GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, session);
+  GNUNET_SCHEDULER_add_now (&destroy_tunnel, session);
+  // send message with product to client
+  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
+                                &prepare_client_response, session);
+  return GNUNET_OK;
+  // if success: terminate the session gracefully, else terminate with error
+}
+
+
+/**
+ * Task run during shutdown.
+ *
+ * @param cls unused
+ * @param tc unused
+ */
+static void
+shutdown_task (void *cls,
+               const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct ServiceSession * curr;
+  struct ServiceSession * next;
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Shutting down, initiating 
cleanup.\n"));
+
+  do_shutdown = GNUNET_YES;
+  // terminate all owned open tunnels.
+  for (curr = from_client_head; NULL != curr; curr = next)
+    {
+      next = curr->next;
+      if (FINALIZED != curr->state)
+        {
+          destroy_tunnel (curr, NULL);
+          curr->state = FINALIZED;
+        }
+    }
+
+  if (my_core)
+    {
+      GNUNET_CORE_disconnect (my_core);
+      my_core = NULL;
+    }
+
+  if (my_mesh)
+    {
+      GNUNET_MESH_disconnect (my_mesh);
+      my_mesh = NULL;
+    }
+}
+
+
+/**
+ * To be called on core init/fail.
+ *
+ * @param cls closure, NULL
+ * @param server handle to the server for this service
+ * @param my_identity the public identity of this peer
+ */
+static void
+core_init (void *cls, struct GNUNET_CORE_Handle *server,
+           const struct GNUNET_PeerIdentity *my_identity)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Core initialized\n"));
+  me = *my_identity;
+}
+
+
+/**
+ * Initialization of the program and message handlers
+ *
+ * @param cls closure
+ * @param server the initialized server
+ * @param c configuration to use
+ */
+static void
+run (void *cls,
+     struct GNUNET_SERVER_Handle *server,
+     const struct GNUNET_CONFIGURATION_Handle *c)
+{
+  static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
+    {&handle_client_request, NULL, 
GNUNET_MESSAGE_TYPE_VECTORPRODUCT_CLIENT_TO_ALICE, 0},
+    {&handle_client_request, NULL, 
GNUNET_MESSAGE_TYPE_VECTORPRODUCT_CLIENT_TO_BOB, 0},
+    {NULL, NULL, 0, 0}
+  };
+  static const struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
+    { &handle_service_request, GNUNET_MESSAGE_TYPE_VECTORPRODUCT_ALICE_TO_BOB, 
0},
+    { &handle_service_response, 
GNUNET_MESSAGE_TYPE_VECTORPRODUCT_BOB_TO_ALICE, 0},
+    {NULL, 0, 0}
+  };
+  static const struct GNUNET_CORE_MessageHandler core_handlers[] = {
+    {NULL, 0, 0}
+  };
+  static GNUNET_MESH_ApplicationType mesh_types[] = {
+    GNUNET_APPLICATION_TYPE_VECTORPRODUCT,
+    GNUNET_APPLICATION_TYPE_END
+  };
+
+  //generate private/public key set
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Generating rsa-key.\n"));
+  generate_keyset ();
+  // register server callbacks and disconnect handler
+  GNUNET_SERVER_add_handlers (server, server_handlers);
+  GNUNET_SERVER_disconnect_notify (server,
+                                   &handle_client_disconnect,
+                                   NULL);
+
+  my_core = GNUNET_CORE_connect (c, NULL, &core_init, NULL, NULL, NULL,
+                                 GNUNET_NO, NULL, GNUNET_NO, core_handlers);
+  if (!my_core)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Connect to CORE failed\n"));
+      return;
+    }
+  my_mesh = GNUNET_MESH_connect (c, NULL,
+                                 &tunnel_incoming_handler,
+                                 &tunnel_destruction_handler,
+                                 mesh_handlers, mesh_types);
+  if (!my_mesh)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Connect to MESH failed\n"));
+      GNUNET_SCHEDULER_shutdown ();
+      return;
+    }
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Mesh initialized\n"));
+  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
+                                &shutdown_task,
+                                NULL);
+}
+
+
+/**
+ * The main function for the vectorproduct service.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc, char *const *argv)
+{
+  return (GNUNET_OK ==
+          GNUNET_SERVICE_run (argc, argv,
+                              "vectorproduct",
+                              GNUNET_SERVICE_OPTION_NONE,
+                              &run, NULL)) ? 0 : 1;
+}
+
+/* end of gnunet-service-ext.c */

Added: gnunet/src/vectorproduct/gnunet-vectorproduct.c
===================================================================
--- gnunet/src/vectorproduct/gnunet-vectorproduct.c                             
(rev 0)
+++ gnunet/src/vectorproduct/gnunet-vectorproduct.c     2013-08-22 13:41:49 UTC 
(rev 28794)
@@ -0,0 +1,410 @@
+/*
+     This file is part of GNUnet.
+     (C) 2013 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 vectorproduct/gnunet-vectorproduct.c
+ * @brief vectorproduct client
+ * @author Christian M. Fuchs
+ */
+#define GCRYPT_NO_DEPRECATED
+#include <gcrypt.h>
+#include <inttypes.h>
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_vectorproduct_service.h"
+#include "gnunet_protocols.h"
+
+#define LOG(kind,...) GNUNET_log_from (kind, 
"gnunet-vectorproduct",__VA_ARGS__)
+/**
+ * Option -p: destination peer identity for checking message-ids with
+ */
+static char *input_peer_id = NULL;
+
+/**
+ * Option -p: destination peer identity for checking message-ids with
+ */
+static char *input_key = NULL;
+
+/**
+ * Option -e: vector to calculate a vectorproduct with
+ */
+static char *input_elements = NULL;
+
+/**
+ * Option -m: message-ids to calculate a vectorproduct with
+ */
+static char *input_mask = NULL;
+
+/**
+ * the count of the messages sent to the service for processing
+ */
+static unsigned short element_count;
+
+/**
+ * the count of the mask bytes
+ */
+unsigned short mask_length = 0;
+
+/**
+ * the count of the number of mask bytes
+ */
+unsigned short mask_bytes;
+
+/**
+ * the array of converted message IDs to send to our service
+ */
+static int32_t * elements = NULL;
+
+/**
+ * the array of converted message IDs to send to our service
+ */
+static unsigned char * mask = NULL;
+
+/**
+ * information about the peer we are comparing with
+ */
+struct GNUNET_PeerIdentity peer;
+
+/**
+ * information about the peer we are comparing with
+ */
+struct GNUNET_HashCode key;
+
+/**
+ * Pointer to the GNUNET_VECTORPRODUCT_Handle
+ */
+struct GNUNET_VECTORPRODUCT_Handle *handle;
+
+/**
+ * Global return value
+ */
+static int ret;
+
+struct GNUNET_VECTORPRODUCT_TestCls
+{
+  struct GNUNET_VECTORPRODUCT_Handle * h;
+};
+
+struct GNUNET_VECTORPRODUCT_TestCls test_cls;
+
+
+/**
+ * Callback called if we are initiating a new computation session
+ * 
+ * @param cls unused
+ * @param status if our job was successfully processed 
+ */
+static void
+responder_callback (void *cls,
+                    const struct GNUNET_HashCode * key,
+                    enum GNUNET_VECTORPRODUCT_ResponseStatus status)
+{
+  ret = -1;
+
+  switch (status)
+    {
+    case GNUNET_VECTORPRODUCT_Status_Success:
+      ret = 0;
+      LOG (GNUNET_ERROR_TYPE_INFO, "Session %s concluded.\n", GNUNET_h2s 
(key));
+      break;
+    case GNUNET_VECTORPRODUCT_Status_InvalidResponse:
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: invalid response\n", 
GNUNET_h2s (key));
+      break;
+    case GNUNET_VECTORPRODUCT_Status_Timeout:
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: timeout\n", GNUNET_h2s 
(key));
+      break;
+    case GNUNET_VECTORPRODUCT_Status_Failure:
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: service failure\n", 
GNUNET_h2s (key));
+    case GNUNET_VECTORPRODUCT_Status_ServiceDisconnected:
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: service 
disconnect!!\n", GNUNET_h2s (key));
+      break;
+    default:
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: return code %d\n", 
GNUNET_h2s (key), (int) status);
+    }
+
+  GNUNET_VECTORPRODUCT_disconnect (handle);
+  GNUNET_SCHEDULER_shutdown ();
+}
+
+
+/**
+ * Callback called if we are initiating a new computation session
+ * 
+ * @param cls unused
+ * @param key unused
+ * @param peer unused
+ * @param status if our job was successfully processed 
+ * @param size size of the msg returned
+ * @param msg the response we got.
+ * @param type of the message received 
+ */
+static void
+requester_callback (void *cls,
+        const struct GNUNET_HashCode * key,
+        const struct GNUNET_PeerIdentity * peer,
+        enum GNUNET_VECTORPRODUCT_ResponseStatus status,
+        const struct GNUNET_VECTORPRODUCT_client_response *msg)
+{
+  uint32_t product_len;
+  ret = -1;
+
+  switch (status)
+    {
+    case GNUNET_VECTORPRODUCT_Status_Success:
+      product_len = ntohl (msg->product_length);
+
+      LOG (GNUNET_ERROR_TYPE_INFO, "Session %s concluded.\n", GNUNET_h2s 
(key));
+
+      if (0 < product_len && NULL != &msg[1])
+        {
+          gcry_mpi_t result;
+          size_t read = 0;
+
+          if (0 != gcry_mpi_scan (&result, GCRYMPI_FMT_USG, &msg[1], 
product_len, &read))
+            LOG (GNUNET_ERROR_TYPE_ERROR, "Could not convert to mpi to 
value!\n");
+          else
+            {
+              unsigned char * buf;
+              gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buf, NULL, result);
+
+              printf ("Successfully computed result for session %s: %s\n", 
GNUNET_h2s (key), buf);
+              ret = 0;
+            }
+        }
+      else
+        { //currently not used, but if we get more info due to MESH we will 
need this
+          LOG (GNUNET_ERROR_TYPE_ERROR, "Service-side error in session %s, 
return code: %d\n", GNUNET_h2s (key), product_len);
+        }
+      break;
+    case GNUNET_VECTORPRODUCT_Status_InvalidResponse:
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: invalid response\n", 
GNUNET_h2s (key));
+      break;
+    case GNUNET_VECTORPRODUCT_Status_Timeout:
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: timeout\n", GNUNET_h2s 
(key));
+      break;
+    case GNUNET_VECTORPRODUCT_Status_Failure:
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: service failure\n", 
GNUNET_h2s (key));
+    case GNUNET_VECTORPRODUCT_Status_ServiceDisconnected:
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Disconnected from service.\n", GNUNET_h2s 
(key));
+      break;
+    default:
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: return code %d\n", 
GNUNET_h2s (key), (int) status);
+    }
+  GNUNET_VECTORPRODUCT_disconnect (handle);
+  GNUNET_SCHEDULER_shutdown ();
+}
+
+
+/**
+ * Main function that will be run by the scheduler.
+ *
+ * @param cls closure
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be 
NULL!)
+ * @param cfg configuration
+ */
+static void
+run (void *cls,
+     char *const *args,
+     const char *cfgfile,
+     const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  char * begin = input_elements;
+  char * end;
+  int32_t element;
+  int i;
+  ret = -1;
+
+  if (NULL == input_elements)
+    {
+      FPRINTF (stderr, "%s", _ ("You must specify at least one message ID to 
check!\n"));
+      return;
+    }
+
+  if (NULL == input_key)
+    {
+      FPRINTF (stderr, "%s", _ ("This program needs a session identifier for 
comparing vectors.\n"));
+      return;
+    }
+
+  if (1 > strnlen (input_key, sizeof (struct GNUNET_HashCode)))
+    {
+      FPRINTF (stderr, _ ("Please give a session key for --input_key!\n"));
+      return;
+    }
+  GNUNET_CRYPTO_hash (input_key, strlen (input_key), &key);
+
+  if (input_peer_id && GNUNET_OK != GNUNET_CRYPTO_hash_from_string 
(input_peer_id,
+                                                                    (struct 
GNUNET_HashCode *) &peer))
+    {
+      FPRINTF (stderr, _ ("Tried to set initiator mode, as peer ID was given. "
+                          "However, `%s' is not a valid peer identifier.\n"),
+               input_peer_id);
+      return;
+    }
+
+  int exit_loop = 0;
+  /* Read input_elements_peer1, and put in elements_peer1 array */
+  do
+    {
+      unsigned int mcount = element_count;
+      //ignore empty rows of ,,,,,,
+      while (*begin == ',')
+        begin++;
+      // get the length of the current element and replace , with null
+      for (end = begin; *end && *end != ','; end++);
+
+      if (*end == '\0')
+        exit_loop = 1;
+
+      if (*end == ',')
+        *end = '\0';
+
+      if (1 != sscanf (begin, "%" SCNd32, &element))
+        {
+          FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
+          return;
+        }
+
+      GNUNET_array_append (elements, mcount, element);
+      element_count++;
+
+      begin = ++end;
+    }
+  while (!exit_loop);
+
+  GNUNET_assert (elements != NULL);
+  GNUNET_assert (element_count > 1);
+  mask_length = element_count / 8 + (element_count % 8 ? 1 : 0);
+  mask = GNUNET_malloc ((element_count / 8) + 2);
+
+  /* Read input_mask_peer1 and read in mask_peer1 array */
+  if (NULL != input_mask)
+    {
+      begin = input_mask;
+      unsigned short mask_count = 0;
+      int exit_loop = 0;
+
+      do
+        {
+          //ignore empty rows of ,,,,,,
+          while (* begin == ',')
+            begin++;
+          // get the length of the current element and replace , with null
+          // gnunet_ascii-armor uses base32, thus we can use , as separator!
+          for (end = begin; *end && *end != ','; end++);
+
+          if (*end == '\0')
+            exit_loop = 1;
+
+          if (*end == ',')
+            *end = '\0';
+
+          if (1 != sscanf (begin, "%" SCNd32, &element))
+            {
+              FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), 
begin);
+              return;
+            }
+
+          GNUNET_assert (mask_count <= element_count);
+
+          if (element)
+            mask[mask_count / 8] = mask[mask_count / 8] | 1 << (mask_count % 
8);
+
+          mask_count++;
+          begin = ++end;
+        }
+      while (!exit_loop);
+      // +1 to see if we would have more data, which would indicate 
malformed/superficial input
+      GNUNET_assert (mask_count == element_count);
+    }
+  else if (input_peer_id)
+    {
+      for (i = 0; i <= mask_length; i++)
+        mask[i] = UCHAR_MAX; // all 1's
+    }
+
+  handle = GNUNET_VECTORPRODUCT_connect (cfg);
+  if (handle == NULL)
+    {
+      FPRINTF (stderr, _ ("Could not connect to the GNUNET Vector Product 
Service\n"));
+      return;
+    }
+
+  test_cls.h = handle;
+
+  if (input_peer_id && !GNUNET_VECTORPRODUCT_request (handle,
+                                                      &key,
+                                                      &peer,
+                                                      element_count,
+                                                      mask_length,
+                                                      elements, mask,
+                                                      GNUNET_TIME_UNIT_MINUTES,
+                                                      &requester_callback,
+                                                      (void *) &test_cls))
+    return;
+  if ( !input_peer_id && !GNUNET_VECTORPRODUCT_prepare_response (handle,
+                                                   &key,
+                                                   element_count,
+                                                   elements,
+                                                   GNUNET_TIME_UNIT_MINUTES,
+                                                   &responder_callback,
+                                                   (void *) &test_cls))
+    return;
+
+  ret = 0;
+}
+
+
+/**
+ * The main function to the vectorproduct client.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc, char *const *argv)
+{
+  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+    {'e', "elements", "\"val1,val2,...,valn\"",
+      gettext_noop ("A comma separated list of elements to compare as vector 
with our remote peer."),
+      1, &GNUNET_GETOPT_set_string, &input_elements},
+    {'m', "mask", "\"0,1,...,maskn\"",
+      gettext_noop ("A comma separated mask to select which elements should 
actually be compared."),
+      1, &GNUNET_GETOPT_set_string, &input_mask},
+    {'p', "peer", "PEERID",
+      gettext_noop ("[Optional] peer to calculate our vectorproduct with. If 
this parameter is not given, the service will wait for a remote peer to compute 
the request."),
+      1, &GNUNET_GETOPT_set_string, &input_peer_id},
+    {'k', "key", "TRANSACTION_ID",
+      gettext_noop ("Transaction ID shared with peer."),
+      1, &GNUNET_GETOPT_set_string, &input_key},
+    GNUNET_GETOPT_OPTION_END
+  };
+
+  return (GNUNET_OK ==
+          GNUNET_PROGRAM_run (argc,
+                              argv,
+                              "gnunet-vectorproduct",
+                              gettext_noop ("Calculate the Vectorproduct with 
a GNUnet peer."),
+                              options, &run, NULL)) ? ret : 1;
+}
+

Added: gnunet/src/vectorproduct/gnunet_vectorproduct.h
===================================================================
--- gnunet/src/vectorproduct/gnunet_vectorproduct.h                             
(rev 0)
+++ gnunet/src/vectorproduct/gnunet_vectorproduct.h     2013-08-22 13:41:49 UTC 
(rev 28794)
@@ -0,0 +1,274 @@
+/*
+      This file is part of GNUnet.
+      (C) 2013 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 include/gnunet_vectorproduct.h
+ * @brief API to the vectorproduct service
+ * @author Christian M. Fuchs
+ */
+
+#ifndef GNUNET_VECTORPRODUCT_H
+#define        GNUNET_VECTORPRODUCT_H
+
+///////////////////////////////////////////////////////////////////////////////
+//                      Defines
+///////////////////////////////////////////////////////////////////////////////
+#define DISABLE_CRYPTO
+
+/**
+ * Length of the key used for encryption
+ */
+#define KEYBITS 2048
+
+/**
+ * When performing our crypto, we may add two encrypted values with each 
+ * a maximal length of GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH.
+ * thus we can receive a slightly longer element (+1 byte)
+ */
+#define PAILLIER_ELEMENT_LENGTH (2*KEYBITS/8 +1)
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+//                     Service Structure Definitions
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Message type passed from requesting service Alice to responding service Bob
+ * to initiate a request and make bob participate in our protocol
+ */
+struct GNUNET_VECTORPRODUCT_service_request {
+  /**
+   * GNUNET message header
+   */
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * how many bytes the mask has
+   */
+  uint16_t mask_length GNUNET_PACKED;
+
+  /**
+   * the length of the publickey contained within this message
+   */
+  uint16_t pk_length GNUNET_PACKED;
+
+  /**
+   * the transaction/session key used to identify a session
+   */
+  struct GNUNET_HashCode key;
+
+  /**
+   * how many elements the vector in payload contains
+   */
+  uint16_t element_count GNUNET_PACKED;
+
+  /**
+   * how many elements are actually included after the mask was applied.
+   */
+  uint16_t used_element_count GNUNET_PACKED;
+
+  /**
+   * followed by mask | public_key | vector[used_element_count]
+   */
+};
+
+/**
+ * Message type passed from responding service Bob to responding service Alice
+ * to complete a request and allow Alice to compute the result
+ */
+struct GNUNET_VECTORPRODUCT_service_response {
+  /**
+   * GNUNET message header
+   */
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * how many elements the vector in payload contains
+   */
+  uint16_t element_count GNUNET_PACKED;
+
+  /**
+   * how many elements are actually included after the mask was applied.
+   */
+  uint16_t used_element_count GNUNET_PACKED;
+
+  /**
+   * the transaction/session key used to identify a session
+   */
+  struct GNUNET_HashCode key;
+
+  /**
+   * followed by s | s' | kp[] | kq[]
+   */
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//                     Service Structure Definitions
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * state a session can be in
+ */
+enum SessionState
+{
+    WAITING_FOR_BOBS_CONNECT,
+    MESSAGE_FROM_RESPONDING_CLIENT_RECEIVED,
+    WAITING_FOR_RESPONSE_FROM_SERVICE,
+    REQUEST_FROM_SERVICE_RECEIVED,
+    FINALIZED
+};
+
+/**
+ * role a peer in a session can assume
+ */
+enum PeerRole
+{
+    ALICE,
+    BOB
+};
+/**
+ * A vectorproduct session which tracks:
+ * 
+ * a request form the client to our final response.
+ * or
+ * a request from a service to us(service).
+ */
+struct ServiceSession
+{
+    /**
+     * the role this peer has
+     */
+    enum PeerRole role;
+
+    /**
+     * session information is kept in a DLL
+     */
+    struct ServiceSession *next;
+
+    /**
+     * session information is kept in a DLL
+     */
+    struct ServiceSession *prev;
+
+    /**
+     * (hopefully) unique transaction ID
+     */
+    struct GNUNET_HashCode key;
+
+    /** 
+     * state of the session
+     */
+    enum SessionState state;
+
+    /**
+     * Alice or Bob's peerID
+     */
+    struct GNUNET_PeerIdentity peer;
+
+    /**
+     * the client this request is related to
+     */
+    struct GNUNET_SERVER_Client * client;
+
+    /**
+     * how many elements we were supplied with from the client
+     */
+    uint16_t element_count;
+
+    /**
+     * how many elements actually are used after applying the mask
+     */
+    uint16_t used_element_count;
+
+    /**
+     * how many bytes the mask is long. 
+     * just for convenience so we don't have to re-re-re calculate it each time
+     */
+    uint16_t mask_length;
+
+    /**
+     * all the vector elements we received
+     */
+    int32_t * vector;
+
+    /**
+     * mask of which elements to check
+     */
+    unsigned char * mask;
+
+    /**
+     * Public key of the remote service, only used by bob
+     */
+    gcry_sexp_t remote_pubkey;
+
+    /**
+     * E(ai)(Bob) or ai(Alice) after applying the mask
+     */
+    gcry_mpi_t * a;
+
+    /**
+     * The computed scalar 
+     */
+    gcry_mpi_t product;
+
+    /**
+     * My transmit handle for the current message to a alice/bob
+     */
+    struct GNUNET_MESH_TransmitHandle * service_transmit_handle;
+
+    /**
+     * My transmit handle for the current message to the client
+     */
+    struct GNUNET_SERVER_TransmitHandle * client_transmit_handle;
+
+    /**
+     * tunnel-handle associated with our mesh handle
+     */
+    struct GNUNET_MESH_Tunnel * tunnel;
+
+};
+
+/**
+ * We need to do a minimum of bookkeeping to maintain track of our transmit 
handles.
+ * each msg is associated with a session and handle. using this information we 
can determine which msg was sent.
+ */
+struct MessageObject
+{
+    /**
+     * The handle used to transmit with this request
+     */
+    void ** transmit_handle;
+
+    /**
+     * The message to send
+     */
+    struct GNUNET_MessageHeader * msg;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GNUNET_VECTORPRODUCT_H */
+

Added: gnunet/src/vectorproduct/test_vectorproduct_api.c
===================================================================
--- gnunet/src/vectorproduct/test_vectorproduct_api.c                           
(rev 0)
+++ gnunet/src/vectorproduct/test_vectorproduct_api.c   2013-08-22 13:41:49 UTC 
(rev 28794)
@@ -0,0 +1,865 @@
+/*
+     This file is part of GNUnet.
+     (C) 2013 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.
+ */
+
+/**
+ * Aim of test_vectorproduct_api : This test creates two peers. Peer1 is the 
+ * responder peer, Bob and Peer2 is the initiator peer, Alice. Both peers
+ * connect to VectorProduct Service, and use the API to issue requests to
+ * service. Test passes, when the expected scalar product is received from the
+ * service.
+ */
+
+/**
+ * @file vectorproduct/testbed_vectorproduct_api.c
+ * @brief VectorProduct API testing between 4 peers using testing API
+ * @author Gaurav Kukreja
+ * @author Christian Fuchs
+ */
+
+#include <string.h>
+
+#include <inttypes.h>
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_testbed_service.h"
+#include "gnunet_common.h"
+#include "gnunet_vectorproduct_service.h"
+#include "gnunet_protocols.h"
+
+#define NUM_PEERS 2
+
+#define LOG(kind,...) GNUNET_log_from (kind, 
"test-vectorproduct-api",__VA_ARGS__)
+
+/**
+ * Structure for holding peer's sockets and IO Handles
+ */
+struct PeerData
+{
+  /**
+   * Handle to testbed peer
+   */
+  struct GNUNET_TESTBED_Peer *peer;
+
+  /**
+   * The service connect operation to stream
+   */
+  struct GNUNET_TESTBED_Operation *op;
+
+  /**
+   * Our Peer id
+   */
+  struct GNUNET_PeerIdentity our_id;
+
+  /**
+   * Pointer to Vector Product Handle
+   */
+  struct GNUNET_VECTORPRODUCT_Handle *vh;
+};
+
+/**
+ * Different states in test setup
+ */
+enum SetupState
+{
+  /**
+   * Get the identity of peer 1
+   */
+  PEER1_GET_IDENTITY,
+
+  /**
+   * Get the identity of peer 2
+   */
+  PEER2_GET_IDENTITY,
+
+  /**
+   * Connect to stream service of peer 1
+   */
+  PEER1_VECTORPRODUCT_CONNECT,
+
+  /**
+   * Connect to stream service of peer 2
+   */
+  PEER2_VECTORPRODUCT_CONNECT
+
+};
+
+/******************************************************************************
+ *** Global Variables                            *****************************
+ 
******************************************************************************/
+
+/**
+ * Maximum allowed message-ids we can check in one go (with one GNUNET_message)
+ */
+static unsigned int max_mids;
+
+/**
+ * Session Key used by both the test peers
+ */
+char input_key[103] = 
"helloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhe";
+
+/**
+ * Input elements for peer1
+ */
+char input_elements_peer1[] = 
"11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11";
+//char input_elements_peer1[] = "11,11,11";
+
+/**
+ * Input Mask for peer 1
+ */
+char input_mask_peer1[] = "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1";
+//char input_mask_peer1[] = "1,1,1";
+
+/**
+ * the array of converted message IDs to send to our service
+ */
+static int32_t * elements_peer1 = NULL;
+
+/**
+ * Number of elements
+ */
+uint16_t element_count_peer1 = 0;
+
+/**
+ * Input elements for peer2
+ */
+char input_elements_peer2[] = 
"11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11";
+//char input_elements_peer2[] = "11,11,11";
+
+/**
+ * Input Mask for peer 2
+ */
+char input_mask_peer2[] = "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1";
+//char input_mask_peer2[] = "1,1,1";
+
+/**
+ * the array of converted message IDs to send to our service
+ */
+static int32_t * elements_peer2 = NULL;
+
+/**
+ * the array of converted message IDs to send to our service
+ */
+static unsigned char * mask_peer2 = NULL;
+
+/**
+ * Number of elements
+ */
+uint16_t element_count_peer2 = 0;
+
+/**
+ * Data context for peer 1
+ */
+static struct PeerData peer1;
+
+/**
+ * Data context for peer 2
+ */
+static struct PeerData peer2;
+
+/**
+ * Various states during test setup
+ */
+static enum SetupState setup_state;
+
+/**
+ * Testbed operation handle
+ */
+static struct GNUNET_TESTBED_Operation *op;
+
+static int ok;
+
+static int responder_ok;
+
+static int requester_ok;
+
+static GNUNET_SCHEDULER_TaskIdentifier abort_task;
+/******************************************************************************
+ *** Static Functions                             *****************************
+ 
******************************************************************************/
+
+static void
+do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Close sockets and stop testing deamons nicely
+ */
+static void
+do_close (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+
+  if (peer1.op != NULL)
+    do_shutdown (&peer1, NULL);
+
+  if (peer2.op != NULL)
+    do_shutdown (&peer2, NULL);
+
+  if (GNUNET_SCHEDULER_NO_TASK != abort_task)
+    GNUNET_SCHEDULER_cancel (abort_task);
+
+  GNUNET_SCHEDULER_shutdown (); /* For shutting down testbed */
+}
+
+/**
+ * Shutdown a peer
+ * 
+ * @param cls pointer to "struct PeerData" of the peer to be disconnected
+ * @param tc Task Context
+ */
+static void
+do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  static int shutdown;
+  shutdown++;
+  struct PeerData* peer = (struct PeerData*) cls;
+
+  if (peer == &peer1)
+    LOG (GNUNET_ERROR_TYPE_INFO, "Disconnecting Peer1\n\n");
+  else if (peer == &peer2)
+    LOG (GNUNET_ERROR_TYPE_INFO, "Disconnecting Peer2\n\n");
+
+  // peer->op contains handle to the TESTBED_connect_service operation
+  // calling operation done, leads to call to vectorproduct_da
+  if (peer->op != NULL)
+    {
+      GNUNET_TESTBED_operation_done (peer->op);
+      peer->op = NULL;
+    }
+
+  if (shutdown >= 2)
+    GNUNET_SCHEDULER_add_now (&do_close, NULL);
+}
+
+
+/**
+ * Something went wrong and timed out. Kill everything and set error flag
+ */
+static void
+do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: ABORT due to Timeout\n");
+  ok = GNUNET_SYSERR;
+  abort_task = 0;
+  do_close (cls, tc);
+}
+
+
+/**
+ * Controller event callback
+ *
+ * @param cls NULL
+ * @param event the controller event
+ */
+static void
+controller_event_cb (void *cls,
+                     const struct GNUNET_TESTBED_EventInformation *event)
+{
+  GNUNET_assert (event->type == GNUNET_TESTBED_ET_OPERATION_FINISHED);
+  
+  switch (setup_state)
+    {
+    case PEER1_VECTORPRODUCT_CONNECT:
+    case PEER2_VECTORPRODUCT_CONNECT:
+      GNUNET_assert (NULL == event->details.operation_finished.emsg);
+      break;
+    default:
+      GNUNET_assert (0);
+    }
+}
+
+
+static void
+responder_callback (void *cls,
+                    const struct GNUNET_HashCode * key,
+                    enum GNUNET_VECTORPRODUCT_ResponseStatus status)
+{
+
+  if (status == GNUNET_VECTORPRODUCT_Status_Failure)
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received status 
failure\n");
+      responder_ok = -1;
+    }
+  else if (status == GNUNET_VECTORPRODUCT_Status_InvalidResponse)
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received status 
invalid response\n");
+      responder_ok = -1;
+    }
+  else if (GNUNET_VECTORPRODUCT_Status_Timeout == status)
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received timeout 
occured\n");
+      responder_ok = -1;
+    }
+  else if (GNUNET_VECTORPRODUCT_Status_ServiceDisconnected == status)
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received service 
disconnected!!\n");
+      responder_ok = -1;
+    }
+  else if (GNUNET_VECTORPRODUCT_Status_Success == status)
+    {
+      LOG (GNUNET_ERROR_TYPE_INFO, "Responder Client expected response 
received!\n");
+      responder_ok = 1;
+    }
+  else
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client status = %d!\n", (int) 
status);
+      responder_ok = -1;
+    }
+  // TODO : Responder Session Complete. Shutdown Test Cleanly!!!
+  //do_shutdown(&peer1, NULL);
+  GNUNET_SCHEDULER_add_now (&do_shutdown, &peer1);
+  return;
+}
+
+
+static void
+requester_callback (void *cls,
+        const struct GNUNET_HashCode * key,
+        const struct GNUNET_PeerIdentity * peer,
+        enum GNUNET_VECTORPRODUCT_ResponseStatus status,
+        const struct GNUNET_VECTORPRODUCT_client_response *msg)
+{
+  uint32_t product_len;
+
+  if (status == GNUNET_VECTORPRODUCT_Status_Failure)
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client received status 
failure\n");
+      requester_ok = -1;
+    }
+  else if (status == GNUNET_VECTORPRODUCT_Status_InvalidResponse)
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client received status 
invalid response\n");
+      requester_ok = -1;
+    }
+  else if (GNUNET_VECTORPRODUCT_Status_Timeout == status)
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client timeout occured\n");
+      requester_ok = -1;
+    }
+  else if (GNUNET_VECTORPRODUCT_Status_ServiceDisconnected == status)
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client service 
disconnected!!\n");
+      requester_ok = -1;
+    }
+  else if (GNUNET_VECTORPRODUCT_Status_Success != status)
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client Status = %d\n", (int) 
status);
+      requester_ok = -1;
+    }
+  else if (GNUNET_VECTORPRODUCT_Status_Success == status)
+    {
+      LOG (GNUNET_ERROR_TYPE_INFO, "Requester Client expected response 
received!\n");
+      product_len = ntohl(msg->product_length);
+      
+      if (0 < product_len)
+        {
+          gcry_mpi_t result;
+          gcry_error_t ret = 0;
+          size_t read = 0;
+          ret = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, &msg[1], product_len, 
&read);
+
+          if (0 != ret)
+            {
+              GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Could not convert to mpi 
to value!\n");
+              ok = -1;
+            }
+          else
+            {
+              uint16_t i = 0;
+
+              // calculate expected product 
+              gcry_mpi_t expected_result;
+              gcry_mpi_t v1;
+              gcry_mpi_t v2;
+              gcry_mpi_t v1_v2_prod;
+
+              expected_result = gcry_mpi_new (0);
+
+              for (i = 0; i < element_count_peer1; i++)
+                {
+                  uint32_t value;
+                  v1_v2_prod = gcry_mpi_new (0);
+
+                  // long to gcry_mpi_t
+                  value = elements_peer1[i] >= 0 ? elements_peer1[i] : 
-elements_peer1[i];
+                  if (elements_peer1[i] < 0)
+                    {
+                      v1 = gcry_mpi_new (0);
+                      gcry_mpi_sub_ui (v1, v1, value);
+                    }
+                  else
+                    v1 = gcry_mpi_set_ui (NULL, value);
+
+                  // long to gcry_mpi_t
+                  value = elements_peer2[i] >= 0 ? elements_peer2[i] : 
-elements_peer2[i];
+                  if (elements_peer2[i] < 0)
+                    {
+                      v2 = gcry_mpi_new (0);
+                      gcry_mpi_sub_ui (v2, v2, value);
+                    }
+                  else
+                    v2 = gcry_mpi_set_ui (NULL, value);
+
+                  gcry_mpi_mul (v1_v2_prod, v1, v2);
+                  gcry_mpi_add (expected_result, expected_result, v1_v2_prod);
+
+                  gcry_mpi_release (v1);
+                  gcry_mpi_release (v2);
+                  gcry_mpi_release (v1_v2_prod);
+
+                }
+              
+              // compare the result
+              if (!gcry_mpi_cmp (expected_result, result))
+                {
+                  LOG (GNUNET_ERROR_TYPE_INFO, "Scalar Product matches 
expected Result!!\n");
+                  requester_ok = 1;
+                }
+              else
+                {
+                  LOG (GNUNET_ERROR_TYPE_WARNING, "Scalar Product DOES NOT 
match expected Result!!\n");
+                  requester_ok = -1;
+                }
+              gcry_mpi_release (result);
+              gcry_mpi_release (expected_result);
+            }
+        }
+      else
+        { //currently not used, but if we get more info due to MESH we will 
need this
+          LOG (GNUNET_ERROR_TYPE_WARNING, "Error during computation of vector 
product, return code: %d\n", product_len);
+          requester_ok = -1;
+        }
+    }
+
+  //do_shutdown(&peer2, NULL);
+  GNUNET_SCHEDULER_add_now (&do_shutdown, &peer2);
+  return;
+}
+
+/**
+ * Prepare the message to be sent by peer2 to its vectorproduct service, to 
+ * initiate a request to peer1.
+ */
+static struct GNUNET_VECTORPRODUCT_QueueEntry *
+requester_request ()
+{
+  unsigned int i;
+  int exit_loop;
+  uint16_t mask_length = 0;
+  char * begin = input_elements_peer2;
+  char * end;
+  int32_t element;
+  struct GNUNET_VECTORPRODUCT_QueueEntry *qe;
+  struct GNUNET_HashCode key;
+  
+  GNUNET_assert (peer2.vh != NULL);
+  
+  GNUNET_CRYPTO_hash (input_key, strlen (input_key), &key);
+
+  /* Read input_elements_peer2, and put in elements_peer2 array */
+  exit_loop = 0;
+  do
+    {
+      unsigned int mcount = element_count_peer2;
+      //ignore empty rows of ,,,,,,
+      while (*begin == ',')
+        begin++;
+      // get the length of the current element and replace , with null
+      for (end = begin; *end && *end != ','; end++);
+
+      if (*end == '\0')
+        exit_loop = 1;
+
+      if (1 != sscanf (begin, "%" SCNd32, &element))
+        {
+          FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
+          ok = -1;
+          return NULL;
+        }
+
+      GNUNET_array_append (elements_peer2, mcount, element);
+      element_count_peer2++;
+
+      begin = ++end;
+    }
+  while (!exit_loop && element_count_peer2 < max_mids);
+  GNUNET_assert (elements_peer2 != NULL);
+  GNUNET_assert (element_count_peer2 >= 1);
+  
+  /* Read input_mask_peer2 and read in mask_peer2 array */
+  mask_length = element_count_peer2 / 8 + (element_count_peer2 % 8 ? 1 : 0);
+  mask_peer2 = GNUNET_malloc ((element_count_peer2 / 8) + 2);
+  GNUNET_assert (NULL != mask_peer2);
+  if (NULL != input_mask_peer2)
+    {
+      begin = input_mask_peer2;
+      unsigned short mask_count = 0;
+      int exit_loop = 0;
+
+      do
+        {
+          //ignore empty rows of ,,,,,,
+          while (* begin == ',')
+            begin++;
+          // get the length of the current element and replace , with null
+          // gnunet_ascii-armor uses base32, thus we can use , as separator!
+          for (end = begin; *end && *end != ','; end++);
+
+          if (*end == '\0')
+            exit_loop = 1;
+
+          if (1 != sscanf (begin, "%" SCNd32, &element))
+            {
+              FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), 
begin);
+              ok = -1;
+              return NULL;
+            }
+
+          GNUNET_assert (mask_count <= element_count_peer2);
+
+          if (element)
+            mask_peer2[mask_count / 8] = mask_peer2[mask_count / 8] | 1 << 
(mask_count % 8);
+
+          mask_count++;
+          begin = ++end;
+        }
+      while (!exit_loop);
+      // +1 to see if we would have more data, which would indicate 
malformed/superficial input
+      GNUNET_assert (mask_count == element_count_peer2);
+    }
+  else
+    {
+      for (i = 0; i <= mask_length; i++)
+        mask_peer2[i] = UCHAR_MAX; // all 1's
+    }
+
+  qe = GNUNET_VECTORPRODUCT_request (peer2.vh,
+                                     &key,
+                                     &peer1.our_id,
+                                     element_count_peer2,
+                                     mask_length,
+                                     elements_peer2, mask_peer2,
+                                     GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_SECONDS, 10),
+                                     &requester_callback,
+                                     NULL);
+
+  if (qe == NULL)
+    {
+      LOG(GNUNET_ERROR_TYPE_ERROR, "Could not send request to vectorproduct 
service! Exitting!");
+      ok = -1;
+      return NULL;
+    }
+
+  return qe;
+}
+
+
+/**
+ * Function prepares the message to be sent by peer1 to its vectorproduct 
service
+ * to prepare response, and wait for a request session to be initiated by peer1
+ */
+static struct GNUNET_VECTORPRODUCT_QueueEntry *
+responder_prepare_response ()
+{
+  GNUNET_assert (peer1.vh != NULL);
+
+  char * begin = input_elements_peer1;
+  char * end;
+  int32_t element;
+  struct GNUNET_VECTORPRODUCT_QueueEntry *qe;
+  struct GNUNET_HashCode key;
+  
+  GNUNET_CRYPTO_hash (input_key, strlen (input_key), &key);
+
+  /* Read input_elements_peer1, and put in elements_peer1 array */
+  int exit_loop = 0;
+  do
+    {
+      unsigned int mcount = element_count_peer1;
+      //ignore empty rows of ,,,,,,
+      while (*begin == ',')
+        begin++;
+      // get the length of the current element and replace , with null
+      for (end = begin; *end && *end != ','; end++);
+
+      if (*end == '\0')
+        exit_loop = 1;
+
+      if (1 != sscanf (begin, "%" SCNd32, &element))
+        {
+          FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
+          ok = -1;
+          return NULL;
+        }
+
+      GNUNET_array_append (elements_peer1, mcount, element);
+      element_count_peer1++;
+
+      begin = ++end;
+    }
+  while (!exit_loop && element_count_peer1 < max_mids);
+  GNUNET_assert (elements_peer1 != NULL);
+  GNUNET_assert (element_count_peer1 >= 1);
+
+  qe = GNUNET_VECTORPRODUCT_prepare_response (peer1.vh,
+                                              &key,
+                                              element_count_peer1,
+                                              elements_peer1,
+                                              GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_SECONDS, 10),
+                                              &responder_callback,
+                                              NULL);
+
+  if (qe == NULL)
+    {
+      LOG(GNUNET_ERROR_TYPE_ERROR, "Could not send request to vectorproduct 
service! Exitting!");
+      ok = -1;
+      return NULL;
+    }
+
+  return qe;
+}
+
+
+/**
+ * Scheduler task to initiate requester client
+ * 
+ * @param cls void* to struct PeerData
+ * @param tc Task Context
+ */
+static void
+request_task(void *cls,
+              const struct GNUNET_SCHEDULER_TaskContext
+              * tc)
+{
+  requester_request();
+  return;
+}
+
+/**
+ * Scheduler task to initiate responder client
+ * 
+ * @param cls void* to struct PeerData
+ * @param tc Task Context
+ */
+static void
+prepare_response_task(void *cls,
+              const struct GNUNET_SCHEDULER_TaskContext
+              * tc)
+{ 
+  responder_prepare_response();
+  return;
+}
+
+
+/**
+ * Adapter function called to destroy a connection to
+ * a service. This function is called when GNUNET_TESTBED_operation_done is
+ * called for peer->op, which holds the handle for 
GNUNET_TESTBED_service_connect
+ * operation.
+ * 
+ * @param cls closure
+ * @param op_result service handle returned from the connect adapter
+ */
+static void
+vectorproduct_da (void *cls, void *op_result)
+{
+  struct PeerData* peer = (struct PeerData*) cls;
+
+  GNUNET_VECTORPRODUCT_disconnect (peer->vh);
+  return;
+}
+
+
+/**
+ * Adapter function called to establish a connection to
+ * a service. This function is called to by GNUNET_TESTBED_service_connect.
+ * 
+ * @param cls closure
+ * @param cfg configuration of the peer to connect to; will be available until
+ *          GNUNET_TESTBED_operation_done() is called on the operation returned
+ *          from GNUNET_TESTBED_service_connect()
+ * @return service handle to return in 'op_result', NULL on error
+ */
+static void *
+vectorproduct_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  struct PeerData *p = cls;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", (&peer1 == 
p) ? 1 : 2,
+              GNUNET_i2s (&p->our_id));
+
+  switch (setup_state)
+    {
+    case PEER1_VECTORPRODUCT_CONNECT:
+      /* Connect peer 2 to vectorproduct service */
+      {
+        peer2.op = GNUNET_TESTBED_service_connect (&peer2, peer2.peer, 
"vectorproduct",
+                                                   NULL, NULL, 
vectorproduct_ca,
+                                                   vectorproduct_da, &peer2);
+        setup_state = PEER2_VECTORPRODUCT_CONNECT;
+      }
+
+      /* Actually connect peer 1 to vectorproduct service */
+      peer1.vh = GNUNET_VECTORPRODUCT_connect (cfg);
+      return peer1.vh;
+
+    case PEER2_VECTORPRODUCT_CONNECT:
+      /* Actually connect peer 2 to vectorproduct service */
+      peer2.vh = GNUNET_VECTORPRODUCT_connect (cfg);
+
+      /* Schedule tasks to initiate request from peer2 and prepare_response 
from peer1 */
+      if(peer1.vh != NULL && peer2.vh != NULL)
+      {
+        GNUNET_SCHEDULER_add_now(&prepare_response_task, &peer1);
+        GNUNET_SCHEDULER_add_now(&request_task, &peer2);
+      }
+      
+      return peer2.vh;
+    default:
+      GNUNET_assert (0);
+    }
+}
+
+
+/**
+ * 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
+peerinfo_cb (void *cb_cls, struct GNUNET_TESTBED_Operation *op_,
+             const struct GNUNET_TESTBED_PeerInformation *pinfo,
+             const char *emsg)
+{
+  GNUNET_assert (NULL == emsg);
+  GNUNET_assert (op == op_);
+  switch (setup_state)
+    {
+    case PEER1_GET_IDENTITY:
+      {
+        memcpy (&peer1.our_id, pinfo->result.id,
+                sizeof (struct GNUNET_PeerIdentity));
+        GNUNET_TESTBED_operation_done (op);
+
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 1 id: %s\n", GNUNET_i2s_full
+                    (&peer1.our_id));
+
+        /* Request for peer id of peer 2*/
+        op = GNUNET_TESTBED_peer_get_information (peer2.peer,
+                                                  GNUNET_TESTBED_PIT_IDENTITY,
+                                                  &peerinfo_cb, NULL);
+        setup_state = PEER2_GET_IDENTITY;
+      }
+      break;
+    case PEER2_GET_IDENTITY:
+      {
+        memcpy (&peer2.our_id, pinfo->result.id,
+                sizeof (struct GNUNET_PeerIdentity));
+        GNUNET_TESTBED_operation_done (op);
+
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 2 id: %s\n", GNUNET_i2s_full
+                    (&peer2.our_id));
+
+        /* Connect peer 1 to vectorproduct service */
+        peer1.op = GNUNET_TESTBED_service_connect (&peer1, peer1.peer, 
"vectorproduct",
+                                                   NULL, NULL, 
vectorproduct_ca,
+                                                   vectorproduct_da, &peer1);
+        setup_state = PEER1_VECTORPRODUCT_CONNECT;
+      }
+      break;
+    default:
+      GNUNET_assert (0);
+    }
+}
+
+
+/**
+ * Signature of a main function for a testcase.
+ *
+ * @param cls closure
+ * @param num_peers number of peers in 'peers'
+ * @param peers handle to peers run in the testbed
+ */
+static void
+test_master (void *cls, unsigned int num_peers,
+             struct GNUNET_TESTBED_Peer **peers)
+{
+  GNUNET_assert (NULL != peers);
+  GNUNET_assert (NULL != peers[0]);
+  GNUNET_assert (NULL != peers[1]);
+  peer1.peer = peers[0];
+  peer2.peer = peers[1];
+  /* Get the peer identity and configuration of peer 1 */
+  op = GNUNET_TESTBED_peer_get_information (peer1.peer,
+                                            GNUNET_TESTBED_PIT_IDENTITY,
+                                            &peerinfo_cb, NULL);
+  setup_state = PEER1_GET_IDENTITY;
+  
+  /* Abort task for stopping test on timeout */
+  abort_task =
+          GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+                                        (GNUNET_TIME_UNIT_SECONDS, 20), 
&do_abort,
+                                        NULL);
+}
+
+
+/**
+ * Main function
+ */
+int
+main (int argc, char **argv)
+{
+  uint64_t event_mask;
+
+  ok = GNUNET_NO;
+  event_mask = 0;
+  event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
+  max_mids = (GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct 
GNUNET_MessageHeader))
+          / sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1;
+
+  (void) GNUNET_TESTBED_test_run ("test_vectorproduct_api",
+                                  "test_vectorproduct_api_data.conf",
+                                  NUM_PEERS, event_mask, &controller_event_cb,
+                                  NULL,
+                                  &test_master, NULL);
+  
+  if (GNUNET_SYSERR == ok)
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Test failing due to some error before 
calling API for request or prepare_response\n");
+      return 1;
+    }
+  else if (GNUNET_SYSERR == responder_ok)
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Test failing due to some error in 
responding_client\n");
+      return 1;
+    }
+  else if (GNUNET_SYSERR == requester_ok)
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Test failing due to some error in 
requesting client\n");
+      return 1;
+    }
+  else
+    return 0;
+}
+
+

Added: gnunet/src/vectorproduct/test_vectorproduct_api_4peers.c
===================================================================
--- gnunet/src/vectorproduct/test_vectorproduct_api_4peers.c                    
        (rev 0)
+++ gnunet/src/vectorproduct/test_vectorproduct_api_4peers.c    2013-08-22 
13:41:49 UTC (rev 28794)
@@ -0,0 +1,1084 @@
+
+/*
+     This file is part of GNUnet.
+     (C) 2013 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.
+ */
+
+/**
+ * AIM OF THIS TEST
+ * 
+ * The aim for the extended test is to verify the queuing functionality in the 
+ * service and the API. The API queues requests received from the clients. The 
+ * service queues requests that are received from other services.
+ * 
+ * To test this, we create 4 peers. peer1 and peer2 are designated responders, 
+ * and peer3 and peer4 are designated as requesters. Each peer calls API for 
the
+ * vectorproduct service accordingly.
+ * 
+ * * peer1 tells the service to prepare response for requests with keys 
+ *   input_key_p1_p3(shared key b/w peer1 and peer3) and input_key_p1_p4. 
+ *   Similarly peer2 tells service to prepare response for requests with keys 
+ *   input_key_p2_p3, and input_key_p2_p4.
+ * * Simultaneously, peer3 tells its service to send a request to peer1 with 
key
+ *   input_key_p1_p3, and a request to peer2 with key input_key_p2_p3. 
Similarly, 
+ *   peer 4 sends requests with appropriate keys.
+ * 
+ * Each peer sends 2 requests to its service, which tests the queuing in API. 
+ * Each service receives 2 requests from other service, which tests the 
queuing 
+ * functionality in the service.
+ */
+
+
+/**
+ * @file vectorproduct/test_vectorproduct_api_4peers.c
+ * @brief Vectorproduct API testing between 4 peers using testing API
+ * @author Gaurav Kukreja
+ * @author Christian Fuchs
+ */
+
+#include <string.h>
+
+#include <inttypes.h>
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_testbed_service.h"
+#include "gnunet_common.h"
+#include "gnunet_vectorproduct_service.h"
+#include "gnunet_protocols.h"
+
+#define LOG(kind,...) GNUNET_log_from (kind, 
"test-vectorproduct-api-4peers",__VA_ARGS__)
+
+#define NUM_PEERS 4
+
+/**
+ * Structure for holding peer's sockets and IO Handles
+ */
+struct PeerData
+{
+  /**
+   * Handle to testbed peer
+   */
+  struct GNUNET_TESTBED_Peer *peer;
+
+  /**
+   * The service connect operation to stream
+   */
+  struct GNUNET_TESTBED_Operation *op;
+
+  /**
+   * Our Peer id
+   */
+  struct GNUNET_PeerIdentity our_id;
+
+  /**
+   * Pointer to Vector Product Handle
+   */
+  struct GNUNET_VECTORPRODUCT_Handle *vh;
+
+  /**
+   * Input elements for peer
+   */
+  char * input_elements;
+
+  /**
+   * Input Mask for peer
+   */
+  char * input_mask;
+
+  /**
+   * 2 Input keys for peer for 2 sessions of each peer
+   */
+  char * input_keys[2];
+
+  /**
+   * Number of requests(or prepare_response) sent by the peer
+   */
+  int request_num;
+
+  /**
+   * Number of callbacks received by the peer
+   */
+  int callback_num;
+
+  /**
+   * PeerData of the peers, this peer will talk to 
+   */
+  struct PeerData * peers[2];
+
+
+};
+
+/**
+ * Different states in test setup
+ */
+enum SetupState
+{
+  /**
+   * Get the identity of peer 1
+   */
+  PEER1_GET_IDENTITY,
+
+  /**
+   * Get the identity of peer 2
+   */
+  PEER2_GET_IDENTITY,
+
+  /**
+   * Get the identity of peer 3
+   */
+  PEER3_GET_IDENTITY,
+
+  /**
+   * Get the identity of peer 4
+   */
+  PEER4_GET_IDENTITY,
+
+  /**
+   * Connect to stream service of peer 1
+   */
+  PEER1_VECTORPRODUCT_CONNECT,
+
+  /**
+   * Connect to stream service of peer 2
+   */
+  PEER2_VECTORPRODUCT_CONNECT,
+
+  /**
+   * Connect to stream service of peer 3
+   */
+  PEER3_VECTORPRODUCT_CONNECT,
+
+  /**
+   * Connect to stream service of peer 4
+   */
+  PEER4_VECTORPRODUCT_CONNECT
+
+};
+
+/******************************************************************************
+ *** Global Variables                            *****************************
+ 
******************************************************************************/
+
+/**
+ * Maximum allowed message-ids we can check in one go (with one GNUNET_message)
+ */
+static unsigned int max_mids;
+
+/**
+ * Session Key used by both the test peers
+ */
+char input_key_p1_p3[103] = 
"111111111111111111111111111111111111111111111111113333333333333333333333333333333333333333333333333333";
+
+/**
+ * Session Key used by both the test peers
+ */
+char input_key_p1_p4[103] = 
"111111111111111111111111111111111111111111111111114444444444444444444444444444444444444444444444444444";
+
+/**
+ * Session Key used by both the test peers
+ */
+char input_key_p2_p3[103] = 
"222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333";
+
+/**
+ * Session Key used by both the test peers
+ */
+char input_key_p2_p4[103] = 
"222222222222222222222222222222222222222222222222224444444444444444444444444444444444444444444444444444";
+
+/**
+ * Input elements for peer1
+ */
+//char input_elements_peer1[] = 
"11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11";
+char input_elements_peer1[] = "11,11,11";
+
+/**
+ * Input Mask for peer 1
+ */
+//char input_mask_peer1[] = "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1";
+char input_mask_peer1[] = "1,1,1";
+
+/**
+ * Input elements for peer2
+ */
+//char input_elements_peer2[] = 
"11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11";
+char input_elements_peer2[] = "11,11,11";
+/**
+ * Input Mask for peer 2
+ */
+//char input_mask_peer2[] = "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1";
+char input_mask_peer2[] = "1,1,1";
+
+/**
+ * Input elements for peer3
+ */
+//char input_elements_peer3[] = 
"11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11";
+char input_elements_peer3[] = "11,11,11";
+
+/**
+ * Input Mask for peer 3
+ */
+//char input_mask_peer3[] = "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1";
+char input_mask_peer3[] = "1,1,1";
+
+/**
+ * Input elements for peer4
+ */
+//char input_elements_peer4[] = 
"11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11";
+char input_elements_peer4[] = "11,11,11";
+/**
+ * Input Mask for peer 4
+ */
+//char input_mask_peer4[] = "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1";
+char input_mask_peer4[] = "1,1,1";
+
+
+/**
+ * Data context for peer 1
+ */
+static struct PeerData peer1;
+
+/**
+ * Data context for peer 2
+ */
+static struct PeerData peer2;
+
+/**
+ * Data context for peer 3
+ */
+static struct PeerData peer3;
+
+/**
+ * Data context for peer 4
+ */
+static struct PeerData peer4;
+
+/**
+ * Various states during test setup
+ */
+static enum SetupState setup_state;
+
+/**
+ * Testbed operation handle
+ */
+static struct GNUNET_TESTBED_Operation *op;
+
+/**
+ * Return value for the test
+ */
+static int ok;
+
+/**
+ * Abort Task for timeout
+ */
+static GNUNET_SCHEDULER_TaskIdentifier abort_task;
+/******************************************************************************
+ *** Static Functions                             *****************************
+ 
******************************************************************************/
+
+static void
+do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Close sockets and stop testing deamons nicely
+ */
+static void
+do_close (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  if (peer1.op != NULL)
+    GNUNET_SCHEDULER_add_now (&do_shutdown, &peer1);
+
+  if (peer2.op != NULL)
+    GNUNET_SCHEDULER_add_now (&do_shutdown, &peer2);
+
+  if (peer3.op != NULL)
+    GNUNET_SCHEDULER_add_now (&do_shutdown, &peer3);
+
+  if (peer4.op != NULL)
+    GNUNET_SCHEDULER_add_now (&do_shutdown, &peer4);
+
+  if (GNUNET_SCHEDULER_NO_TASK != abort_task)
+    GNUNET_SCHEDULER_cancel (abort_task);
+
+  GNUNET_SCHEDULER_shutdown (); /* For shutting down testbed */
+}
+
+
+static void
+do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  static int shutdown;
+  shutdown++;
+  struct PeerData* peer = (struct PeerData*) cls;
+
+  if (peer == &peer1)
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down Peer 1!!! \n");
+  else if (peer == &peer2)
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down Peer 2!!! \n");
+  else if (peer == &peer3)
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down Peer 3!!! \n");
+  else if (peer == &peer4)
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down Peer 4!!! \n");
+
+  // peer->op contains handle to the TESTBED_connect_service operation
+  // calling operation done, leads to call to vectorproduct_da
+  GNUNET_TESTBED_operation_done (peer->op);
+  peer->op = NULL;
+
+  if (shutdown == 4)
+    GNUNET_SCHEDULER_add_now (&do_close, NULL);
+}
+
+
+/**
+ * Something went wrong and timed out. Kill everything and set error flag
+ */
+static void
+do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: ABORT due to Timeout\n");
+  ok = GNUNET_SYSERR;
+  abort_task = 0;
+  do_close (cls, tc);
+}
+
+
+/**
+ * Controller event callback
+ *
+ * @param cls NULL
+ * @param event the controller event
+ */
+static void
+controller_event_cb (void *cls,
+                     const struct GNUNET_TESTBED_EventInformation *event)
+{
+  switch (event->type)
+    {
+    case GNUNET_TESTBED_ET_OPERATION_FINISHED:
+      switch (setup_state)
+        {
+        case PEER1_VECTORPRODUCT_CONNECT:
+        case PEER2_VECTORPRODUCT_CONNECT:
+          GNUNET_assert (NULL == event->details.operation_finished.emsg);
+          break;
+        default:
+          GNUNET_assert (0);
+        }
+      break;
+    default:
+      GNUNET_assert (0);
+    }
+}
+
+
+static void
+responder_callback (void *cls,
+                    const struct GNUNET_HashCode * key,
+                    enum GNUNET_VECTORPRODUCT_ResponseStatus status)
+{
+  struct PeerData * peer = cls;
+
+  peer->callback_num++;
+
+  if (peer == &peer1)
+    {
+        LOG (GNUNET_ERROR_TYPE_DEBUG, "Peer1 received callback!!!\n");
+    }
+  else if (peer == &peer2)
+    {
+        LOG (GNUNET_ERROR_TYPE_DEBUG, "Peer2 received callback!!!\n");
+    }
+  else
+    LOG (GNUNET_ERROR_TYPE_ERROR, "Requester callback received, but peer is 
neither peer1 nor peer2!!!\n");
+
+
+  if (status == GNUNET_VECTORPRODUCT_Status_Failure)
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Responder Client received status 
failure\n");
+      ok = -1;
+    }
+  else if (status == GNUNET_VECTORPRODUCT_Status_InvalidResponse)
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Responder Client received status invalid 
response\n");
+      ok = -1;
+    }
+  else if (GNUNET_VECTORPRODUCT_Status_Timeout == status)
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Responder Client received timeout 
occured\n");
+      ok = -1;
+    }
+  else if (GNUNET_VECTORPRODUCT_Status_ServiceDisconnected == status)
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Responder Client received service 
disconnected!!\n");
+      ok = -1;
+    }
+  else if (GNUNET_VECTORPRODUCT_Status_Success == status)
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "Responder Client expected response 
received!\n");
+      ok = 1;
+    }
+  else
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Responder Client status = %d!\n", (int) 
status);
+      ok = -1;
+    }
+
+  // TODO : Responder Session Complete. Shutdown Test Cleanly!!!
+  if (peer->callback_num == 2)
+    GNUNET_SCHEDULER_add_now (&do_shutdown, peer);
+}
+
+
+static void
+requester_callback (void *cls,
+                    const struct GNUNET_HashCode * key,
+                    const struct GNUNET_PeerIdentity * peer,
+                    enum GNUNET_VECTORPRODUCT_ResponseStatus status,
+                    const struct GNUNET_VECTORPRODUCT_client_response *msg)
+{
+  struct PeerData * peer_ = cls;
+  uint32_t product_len;
+
+  peer_->callback_num++;
+  
+  if (peer_ == &peer3)
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "Peer3 received callback!!!\n");
+    }
+  else if (peer_ == &peer4)
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "Peer4 received callback!!!\n");
+    }
+  else
+    LOG (GNUNET_ERROR_TYPE_ERROR, "Requester callback received, but peer is 
neither peer3 nor peer4!!!\n");
+
+
+  if (status == GNUNET_VECTORPRODUCT_Status_Failure)
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Requester Client received status 
failure\n");
+      ok = -1;
+    }
+  else if (status == GNUNET_VECTORPRODUCT_Status_InvalidResponse)
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Requester Client received status invalid 
response\n");
+      ok = -1;
+    }
+  else if (GNUNET_VECTORPRODUCT_Status_Timeout == status)
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Requester Client timeout occured\n");
+      ok = -1;
+    }
+  else if (GNUNET_VECTORPRODUCT_Status_ServiceDisconnected == status)
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Requester Client service 
disconnected!!\n");
+      ok = -1;
+    }
+  else if (GNUNET_VECTORPRODUCT_Status_Success != status)
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Requester Client Status = %d\n", (int) 
status);
+      ok = -1;
+    }
+  else if (GNUNET_VECTORPRODUCT_Status_Success == status)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Requester client received status 
successful!\n");
+      product_len = ntohl (msg->product_length);
+
+      if (0 < product_len)
+        {
+          gcry_mpi_t result;
+          gcry_error_t ret = 0;
+          size_t read = 0;
+
+          ret = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, (void*) &(msg[1]), 
product_len, &read);
+
+          if (0 != ret)
+            {
+              GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not convert to mpi 
to value!\n");
+            }
+          else
+            {
+              gcry_mpi_release (result);
+            }
+          ok = 1;
+        }
+      else
+        { 
+          //currently not used, but if we get more info due to MESH we will 
need this
+          LOG (GNUNET_ERROR_TYPE_ERROR, "Error during computation of vector 
product, return code: %d\n", product_len);
+          ok = -1;
+        }
+    }
+
+  if (peer_->callback_num == 2)
+    GNUNET_SCHEDULER_add_now (&do_shutdown, peer_);
+}
+
+
+static struct GNUNET_VECTORPRODUCT_QueueEntry *
+requester_request (char * input_elements,
+                   char * input_mask,
+                   char * input_key,
+                   struct PeerData * peer,
+                   struct PeerData * to_peer)
+{
+  
+
+  unsigned int i;
+  uint16_t element_count = 0;
+  int32_t * elements = NULL;
+  uint16_t mask_length = 0;
+  unsigned char * mask = NULL;
+  int32_t element;
+  struct GNUNET_VECTORPRODUCT_QueueEntry *qe;
+  struct GNUNET_HashCode key;
+  int exit_loop;
+  char * begin = input_elements;
+  char * end;
+  
+  GNUNET_assert (peer->vh != NULL);
+  
+  GNUNET_CRYPTO_hash_from_string (input_key, &key);
+  
+  exit_loop = 0;
+  /* Read input_elements, and put in elements array */
+  do
+    {
+      unsigned int mcount = element_count;
+      //ignore empty rows of ,,,,,,
+      while (*begin == ',')
+        begin++;
+      // get the length of the current element and replace , with null
+      for (end = begin; *end && *end != ','; end++);
+
+      if (*end == '\0')
+        exit_loop = 1;
+
+
+      if (1 != sscanf (begin, "%" SCNd32, &element))
+        {
+          FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
+          ok = -1;
+          return NULL;
+        }
+      
+      GNUNET_array_append (elements, mcount, element);
+      element_count++;
+
+      begin = ++end;
+    }
+  while (!exit_loop && element_count < max_mids);
+  GNUNET_assert (elements != NULL);
+  GNUNET_assert (element_count >= 1);
+  
+  /* Read input_mask and read in mask array */
+  mask_length = element_count / 8 + (element_count % 8 ? 1 : 0);
+  mask = GNUNET_malloc ((element_count / 8) + 2);
+  GNUNET_assert (NULL != mask);
+  if (NULL != input_mask)
+    {
+      begin = input_mask;
+      unsigned short mask_count = 0;
+      int exit_loop = 0;
+
+      do
+        {
+          //ignore empty rows of ,,,,,,
+          while (* begin == ',')
+            begin++;
+          // get the length of the current element and replace , with null
+          // gnunet_ascii-armor uses base32, thus we can use , as separator!
+          for (end = begin; *end && *end != ','; end++);
+
+          if (*end == '\0')
+            exit_loop = 1;
+
+
+          if (1 != sscanf (begin, "%" SCNd32, &element))
+            {
+              FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), 
begin);
+              ok = -1;
+              return NULL;
+            }
+
+          GNUNET_assert (mask_count <= element_count);
+
+          if (element)
+            mask[mask_count / 8] = mask[mask_count / 8] | 1 << (mask_count % 
8);
+
+          mask_count++;
+          begin = ++end;
+        }
+      while (!exit_loop);
+      // +1 to see if we would have more data, which would indicate 
malformed/superficial input
+      GNUNET_assert (mask_count == element_count);
+    }
+  else
+    {
+      for (i = 0; i <= mask_length; i++)
+        mask[i] = UCHAR_MAX; // all 1's
+    }
+  
+  qe = GNUNET_VECTORPRODUCT_request (peer->vh,
+                                     &key,
+                                     &to_peer->our_id,
+                                     element_count,
+                                     mask_length,
+                                     elements, mask,
+                                     GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_SECONDS, 60),
+                                     &requester_callback,
+                                     peer);
+
+  if (qe == NULL)
+    {
+      LOG(GNUNET_ERROR_TYPE_WARNING, "Could not send request to vectorproduct 
service! Exitting!");
+      ok = -1;
+      return NULL;
+    }
+
+  return qe;
+}
+
+
+/**
+ * Function prepares the message to be sent by peer1 to its vectorproduct 
service
+ * to prepare response, and wait for a request session to be initiated by peer1
+ */
+static struct GNUNET_VECTORPRODUCT_QueueEntry *
+responder_prepare_response (char * input_elements,
+                            char * input_mask,
+                            char * input_key,
+                            struct PeerData * peer)
+{
+  GNUNET_assert (peer->vh != NULL);
+
+  unsigned int i;
+  uint16_t element_count = 0;
+  int32_t * elements = NULL;
+  unsigned short mask_length = 0;
+  unsigned char * mask = NULL;
+  int32_t element;
+  struct GNUNET_VECTORPRODUCT_QueueEntry *qe;
+  struct GNUNET_HashCode key;
+  int exit_loop;
+  char * begin;
+  char * end;
+  
+  GNUNET_CRYPTO_hash_from_string (input_key, &key);
+  
+  /* Read input_elements, and put in elements array */
+  exit_loop = 0;
+  begin = input_elements;
+  do
+    {
+      unsigned int mcount = element_count;
+      //ignore empty rows of ,,,,,,
+      while (*begin == ',')
+        begin++;
+      // get the length of the current element and replace , with null
+      for (end = begin; *end && *end != ','; end++);
+
+      if (*end == '\0')
+        exit_loop = 1;
+
+      if (1 != sscanf (begin, "%" SCNd32, &element))
+        {
+          FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
+          ok = -1;
+          return NULL;
+        }
+
+      GNUNET_array_append (elements, mcount, element);
+      element_count++;
+
+      begin = ++end;
+    }
+  while (!exit_loop && element_count < max_mids);
+  GNUNET_assert (elements != NULL);
+  GNUNET_assert (element_count >= 1);
+  
+  /* Read input_mask and read in mask array */
+  mask_length = element_count / 8 + (element_count % 8 ? 1 : 0);
+  mask = GNUNET_malloc ((element_count / 8) + 2);
+  GNUNET_assert (NULL != mask);
+  if (NULL != input_mask)
+    {
+      begin = input_mask;
+      unsigned short mask_count = 0;
+      int exit_loop = 0;
+
+      do
+        {
+          //ignore empty rows of ,,,,,,
+          while (* begin == ',')
+            begin++;
+          // get the length of the current element and replace , with null
+          // gnunet_ascii-armor uses base32, thus we can use , as separator!
+          for (end = begin; *end && *end != ','; end++);
+
+          if (*end == '\0')
+            exit_loop = 1;
+
+          if (1 != sscanf (begin, "%" SCNd32, &element))
+            {
+              FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), 
begin);
+              ok = -1;
+              return NULL;
+            }
+
+          GNUNET_assert (mask_count <= element_count);
+
+          if (element)
+            mask[mask_count / 8] = mask[mask_count / 8] | 1 << (mask_count % 
8);
+
+          mask_count++;
+          begin = ++end;
+        }
+      while (!exit_loop);
+      // +1 to see if we would have more data, which would indicate 
malformed/superficial input
+      GNUNET_assert (mask_count == element_count);
+    }
+  else
+    {
+      for (i = 0; i <= mask_length; i++)
+        mask[i] = UCHAR_MAX; // all 1's
+    }
+
+  qe = GNUNET_VECTORPRODUCT_prepare_response (peer->vh,
+                                              &key,
+                                              element_count,
+                                              elements,
+                                              GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_SECONDS, 60),
+                                              &responder_callback,
+                                              peer);
+
+  if (qe == NULL)
+    {
+      LOG(GNUNET_ERROR_TYPE_ERROR, "Could not send request to vectorproduct 
service! Exitting!");
+      ok = -1;
+      return NULL;
+    }
+
+  return qe;
+}
+
+
+static void
+request_task (void *cls,
+              const struct GNUNET_SCHEDULER_TaskContext
+              * tc)
+{
+  struct PeerData * peer = cls;
+
+  requester_request (peer->input_elements, peer->input_mask, 
peer->input_keys[peer->request_num], peer, peer->peers[peer->request_num]);
+  peer->request_num++;
+  return;
+}
+
+
+static void
+prepare_response_task (void *cls,
+                       const struct GNUNET_SCHEDULER_TaskContext
+                       * tc)
+{
+  struct PeerData * peer = cls;
+
+  responder_prepare_response (peer->input_elements, peer->input_mask, 
peer->input_keys[peer->request_num], peer);
+  peer->request_num++;
+  return;
+}
+
+
+/**
+ * Adapter function called to destroy a connection to
+ * a service. This function is called when GNUNET_TESTBED_operation_done is
+ * called for peer->op, which holds the handle for 
GNUNET_TESTBED_service_connect
+ * operation.
+ * 
+ * @param cls closure
+ * @param op_result service handle returned from the connect adapter
+ */
+static void
+vectorproduct_da (void *cls, void *op_result)
+{
+  struct PeerData* peer = (struct PeerData*) cls;
+
+  GNUNET_VECTORPRODUCT_disconnect (peer->vh);
+  return;
+
+  GNUNET_assert (0);
+}
+
+
+/**
+ * Adapter function called to establish a connection to
+ * a service. This function is called to by GNUNET_TESTBED_service_connect.
+ * 
+ * @param cls closure
+ * @param cfg configuration of the peer to connect to; will be available until
+ *          GNUNET_TESTBED_operation_done() is called on the operation returned
+ *          from GNUNET_TESTBED_service_connect()
+ * @return service handle to return in 'op_result', NULL on error
+ */
+static void *
+vectorproduct_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  struct PeerData *p = cls;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", (&peer1 == 
p) ? 1 : 2,
+              GNUNET_i2s (&p->our_id));
+
+  switch (setup_state)
+    {
+    case PEER1_VECTORPRODUCT_CONNECT:
+      /* Connect peer 2 to vectorproduct service */
+      {
+        peer2.op = GNUNET_TESTBED_service_connect (&peer2, peer2.peer, 
"vectorproduct",
+                                                   NULL, NULL, 
vectorproduct_ca,
+                                                   vectorproduct_da, &peer2);
+        setup_state = PEER2_VECTORPRODUCT_CONNECT;
+      }
+
+      peer1.vh = GNUNET_VECTORPRODUCT_connect (cfg);
+      return peer1.vh;
+
+    case PEER2_VECTORPRODUCT_CONNECT:
+      /* Connect peer 3 to vectorproduct service */
+      {
+        peer3.op = GNUNET_TESTBED_service_connect (&peer3, peer3.peer, 
"vectorproduct",
+                                                   NULL, NULL, 
vectorproduct_ca,
+                                                   vectorproduct_da, &peer3);
+        setup_state = PEER3_VECTORPRODUCT_CONNECT;
+      }
+
+      peer2.vh = GNUNET_VECTORPRODUCT_connect (cfg);
+      return peer2.vh;
+
+    case PEER3_VECTORPRODUCT_CONNECT:
+      /* Connect peer 4 to vectorproduct service */
+      {
+        peer4.op = GNUNET_TESTBED_service_connect (&peer4, peer4.peer, 
"vectorproduct",
+                                                   NULL, NULL, 
vectorproduct_ca,
+                                                   vectorproduct_da, &peer4);
+        setup_state = PEER4_VECTORPRODUCT_CONNECT;
+      }
+
+      peer3.vh = GNUNET_VECTORPRODUCT_connect (cfg);
+      return peer3.vh;
+
+    case PEER4_VECTORPRODUCT_CONNECT:
+      peer4.vh = GNUNET_VECTORPRODUCT_connect (cfg);
+
+      /* Schedule the tasks to issue prepare_response calls from peer1 and 
peer2
+       * for peer3 and peer4.
+       */
+      GNUNET_SCHEDULER_add_now (&prepare_response_task, &peer1);
+      GNUNET_SCHEDULER_add_now (&prepare_response_task, &peer1);
+      GNUNET_SCHEDULER_add_now (&prepare_response_task, &peer2);
+      GNUNET_SCHEDULER_add_now (&prepare_response_task, &peer2);
+
+      /* 
+       * Schedule the tasks to issue requests calls from peer3 and peer4
+       * to peer1 and peer2
+       */
+      GNUNET_SCHEDULER_add_now (&request_task, &peer3);
+      GNUNET_SCHEDULER_add_now (&request_task, &peer3);
+      GNUNET_SCHEDULER_add_now (&request_task, &peer4);
+      GNUNET_SCHEDULER_add_now (&request_task, &peer4);
+
+      return peer2.vh;
+    default:
+      GNUNET_assert (0);
+    }
+}
+
+
+/**
+ * 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
+peerinfo_cb (void *cb_cls, struct GNUNET_TESTBED_Operation *op_,
+             const struct GNUNET_TESTBED_PeerInformation *pinfo,
+             const char *emsg)
+{
+  GNUNET_assert (NULL == emsg);
+  GNUNET_assert (op == op_);
+  switch (setup_state)
+    {
+    case PEER1_GET_IDENTITY:
+      {
+        memcpy (&peer1.our_id, pinfo->result.id,
+                sizeof (struct GNUNET_PeerIdentity));
+        GNUNET_TESTBED_operation_done (op);
+
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 1 id: %s\n", GNUNET_i2s_full
+                    (&peer1.our_id));
+
+        /* Request for peer id of peer 2*/
+        op = GNUNET_TESTBED_peer_get_information (peer2.peer,
+                                                  GNUNET_TESTBED_PIT_IDENTITY,
+                                                  &peerinfo_cb, NULL);
+        setup_state = PEER2_GET_IDENTITY;
+      }
+      break;
+    case PEER2_GET_IDENTITY:
+      {
+        memcpy (&peer2.our_id, pinfo->result.id,
+                sizeof (struct GNUNET_PeerIdentity));
+        GNUNET_TESTBED_operation_done (op);
+
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 2 id: %s\n", GNUNET_i2s_full
+                    (&peer2.our_id));
+
+        /* Request for peer id of peer 3*/
+        op = GNUNET_TESTBED_peer_get_information (peer3.peer,
+                                                  GNUNET_TESTBED_PIT_IDENTITY,
+                                                  &peerinfo_cb, NULL);
+        setup_state = PEER3_GET_IDENTITY;
+      }
+      break;
+    case PEER3_GET_IDENTITY:
+      {
+        memcpy (&peer3.our_id, pinfo->result.id,
+                sizeof (struct GNUNET_PeerIdentity));
+        GNUNET_TESTBED_operation_done (op);
+
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 3 id: %s\n", GNUNET_i2s_full
+                    (&peer3.our_id));
+
+        /* Request for peer id of peer 4*/
+        op = GNUNET_TESTBED_peer_get_information (peer4.peer,
+                                                  GNUNET_TESTBED_PIT_IDENTITY,
+                                                  &peerinfo_cb, NULL);
+        setup_state = PEER4_GET_IDENTITY;
+      }
+      break;
+    case PEER4_GET_IDENTITY:
+      {
+        memcpy (&peer4.our_id, pinfo->result.id,
+                sizeof (struct GNUNET_PeerIdentity));
+        GNUNET_TESTBED_operation_done (op);
+
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 2 id: %s\n", GNUNET_i2s_full
+                    (&peer2.our_id));
+
+        /* Connect peer 1 to vectorproduct service */
+        peer1.op = GNUNET_TESTBED_service_connect (&peer1, peer1.peer, 
"vectorproduct",
+                                                   NULL, NULL, 
vectorproduct_ca,
+                                                   vectorproduct_da, &peer1);
+        setup_state = PEER1_VECTORPRODUCT_CONNECT;
+      }
+      break;
+    default:
+      GNUNET_assert (0);
+    }
+}
+
+
+/**
+ * Signature of a main function for a testcase.
+ *
+ * @param cls closure
+ * @param num_peers number of peers in 'peers'
+ * @param peers handle to peers run in the testbed
+ */
+static void
+test_master (void *cls, unsigned int num_peers,
+             struct GNUNET_TESTBED_Peer **peers)
+{
+  GNUNET_assert (NULL != peers);
+  GNUNET_assert (NULL != peers[0]);
+  GNUNET_assert (NULL != peers[1]);
+  GNUNET_assert (NULL != peers[2]);
+  GNUNET_assert (NULL != peers[3]);
+  peer1.peer = peers[0];
+  peer1.input_elements = input_elements_peer1;
+  peer1.input_mask = input_mask_peer1;
+  peer1.request_num = 0;
+  peer1.callback_num = 0;
+  peer1.input_keys[0] = input_key_p1_p3;
+  peer1.input_keys[1] = input_key_p1_p4;
+
+  peer2.peer = peers[1];
+  peer2.input_elements = input_elements_peer2;
+  peer2.input_mask = input_mask_peer2;
+  peer2.request_num = 0;
+  peer2.callback_num = 0;
+  peer2.input_keys[0] = input_key_p2_p3;
+  peer2.input_keys[1] = input_key_p2_p4;
+
+  peer3.peer = peers[2];
+  peer3.input_elements = input_elements_peer3;
+  peer3.input_mask = input_mask_peer3;
+  peer3.request_num = 0;
+  peer3.callback_num = 0;
+  peer3.input_keys[0] = input_key_p1_p3;
+  peer3.input_keys[1] = input_key_p2_p3;
+  peer3.peers[0] = &peer1;
+  peer3.peers[1] = &peer2;
+
+
+  peer4.peer = peers[3];
+  peer4.input_elements = input_elements_peer4;
+  peer4.input_mask = input_mask_peer4;
+  peer4.request_num = 0;
+  peer4.callback_num = 0;
+  peer4.input_keys[0] = input_key_p1_p4;
+  peer4.input_keys[1] = input_key_p2_p4;
+  peer4.peers[0] = &peer1;
+  peer4.peers[1] = &peer2;
+  
+  /* Get the peer identity and configuration of peer 1 */
+  op = GNUNET_TESTBED_peer_get_information (peer1.peer,
+                                            GNUNET_TESTBED_PIT_IDENTITY,
+                                            &peerinfo_cb, NULL);
+  setup_state = PEER1_GET_IDENTITY;
+  abort_task =
+          GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+                                        (GNUNET_TIME_UNIT_SECONDS, 120), 
&do_abort,
+                                        NULL);
+}
+
+
+/**
+ * Main function
+ */
+int
+main (int argc, char **argv)
+{
+  uint64_t event_mask;
+
+  ok = GNUNET_NO;
+  event_mask = 0;
+  event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
+  max_mids = (GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct 
GNUNET_MessageHeader))
+          / sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1;
+  (void) GNUNET_TESTBED_test_run ("test_vectorproduct_api_4peers",
+                                  "test_vectorproduct_api_data.conf",
+                                  NUM_PEERS, event_mask, &controller_event_cb,
+                                  NULL,
+                                  &test_master, NULL);
+  if (GNUNET_SYSERR == ok)
+    return 1;
+  return 0;
+}

Added: gnunet/src/vectorproduct/test_vectorproduct_api_data.conf
===================================================================
--- gnunet/src/vectorproduct/test_vectorproduct_api_data.conf                   
        (rev 0)
+++ gnunet/src/vectorproduct/test_vectorproduct_api_data.conf   2013-08-22 
13:41:49 UTC (rev 28794)
@@ -0,0 +1,96 @@
+[arm]
+DEFAULTSERVICES = core transport vectorproduct mesh testbed
+PORT = 12366
+
+[core]
+PORT = 12092
+
+[vectorproduct]
+#AUTOSTART = YES
+BINARY = gnunet-service-vectorproduct
+UNIXPATH = /tmp/gnunet-service-vectorproduct.sock
+HOME = $SERVICEHOME
+HOSTNAME = localhost
+PORT = 2087
+
+[testbed]
+OVERLAY_TOPOLOGY = CLIQUE
+
+[lockmanager]
+AUTOSTART = NO
+ACCEPT_FROM = 127.0.0.1;
+HOSTNAME = localhost
+PORT = 12101
+
+[statistics]
+AUTOSTART = YES
+ACCEPT_FROM = 127.0.0.1;
+PORT = 12102
+
+[fs]
+AUTOSTART = NO
+
+[resolver]
+AUTOSTART = NO
+
+[mesh]
+# AUTOSTART = YES
+ACCEPT_FROM = 127.0.0.1;
+HOSTNAME = localhost
+PORT = 10700
+# PREFIX = valgrind --leak-check=full
+# PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args
+
+[dht]
+AUTOSTART = YES
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+HOSTNAME = localhost
+PORT = 12100
+
+[block]
+plugins = dht test
+
+[dhtcache]
+QUOTA = 1 MB
+DATABASE = sqlite
+
+[transport]
+PLUGINS = tcp
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+NEIGHBOUR_LIMIT = 50
+PORT = 12365
+
+[ats]
+WAN_QUOTA_OUT = 3932160
+WAN_QUOTA_IN = 3932160
+
+[transport-tcp]
+TIMEOUT = 300 s
+PORT = 12368
+
+[TESTING]
+WEAKRANDOM = YES
+
+[gnunetd]
+HOSTKEY = $SERVICEHOME/.hostkey
+
+[PATHS]
+SERVICEHOME = /tmp/test-vectorproduct/
+
+[dns]
+AUTOSTART = NO
+
+[nse]
+AUTOSTART = NO
+
+[vpn]
+AUTOSTART = NO
+
+[nat]
+RETURN_LOCAL_ADDRESSES = YES
+
+[consensus]
+AUTOSTART = NO
+

Added: gnunet/src/vectorproduct/test_vectorproduct_api_regression.c
===================================================================
--- gnunet/src/vectorproduct/test_vectorproduct_api_regression.c                
                (rev 0)
+++ gnunet/src/vectorproduct/test_vectorproduct_api_regression.c        
2013-08-22 13:41:49 UTC (rev 28794)
@@ -0,0 +1,852 @@
+
+/*
+     This file is part of GNUnet.
+     (C) 2013 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 vectorproduct/test_vectorproduct_api_regression.c
+ * @brief VectorProduct API regression test
+ * @author Gaurav Kukreja
+ * @author Christian Fuchs
+ */
+
+/**
+ * AIM of the regression test
+ * 
+ * This test tries to check whether the service can handle abrupt client 
disconnect.
+ * 
+ * 1. We create a responder peer, and ask the service to prepare_response. 
After this,
+ *    we disconnect responder peer from service.
+ * 
+ * 2. Then we create a requester peer, and ask service to request another 
peer. We
+ *    should check that the service on responder peer is still active and 
receives
+ *    request from the requester. We then disconnect requester peer from 
service. Both
+ *    the requester and responder service should handle this cleanly.
+ */
+
+#include <string.h>
+
+#include <inttypes.h>
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_testbed_service.h"
+#include "gnunet_common.h"
+#include "gnunet_vectorproduct_service.h"
+#include "gnunet_protocols.h"
+
+#define LOG(kind,...) GNUNET_log_from (kind, 
"test-vectorproduct-api-regression",__VA_ARGS__)
+#define NUM_PEERS 2
+
+/**
+ * Structure for holding peer's sockets and IO Handles
+ */
+struct PeerData
+{
+  /**
+   * Handle to testbed peer
+   */
+  struct GNUNET_TESTBED_Peer *peer;
+
+  /**
+   * The service connect operation to stream
+   */
+  struct GNUNET_TESTBED_Operation *op;
+
+  /**
+   * Our Peer id
+   */
+  struct GNUNET_PeerIdentity our_id;
+
+  /**
+   * Pointer to Vector Product Handle
+   */
+  struct GNUNET_VECTORPRODUCT_Handle *vh;
+};
+
+/**
+ * Different states in test setup
+ */
+enum SetupState
+{
+  /**
+   * Get the identity of peer 1
+   */
+  PEER1_GET_IDENTITY,
+
+  /**
+   * Get the identity of peer 2
+   */
+  PEER2_GET_IDENTITY,
+
+  /**
+   * Connect to stream service of peer 1
+   */
+  PEER1_VECTORPRODUCT_CONNECT,
+
+  /**
+   * Connect to stream service of peer 2
+   */
+  PEER2_VECTORPRODUCT_CONNECT
+
+};
+
+/******************************************************************************
+ *** Global Variables                            *****************************
+ 
******************************************************************************/
+
+/**
+ * Maximum allowed message-ids we can check in one go (with one GNUNET_message)
+ */
+static unsigned int max_mids;
+
+/**
+ * Session Key used by both the test peers
+ */
+char input_key[103] = 
"helloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhe";
+
+/**
+ * Input elements for peer1
+ */
+//char input_elements_peer1[] = 
"11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11";
+char input_elements_peer1[] = "11,11,11";
+
+/**
+ * Input Mask for peer 1
+ */
+//char input_mask_peer1[] = "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1";
+char input_mask_peer1[] = "1,1,1";
+
+/**
+ * the array of converted message IDs to send to our service
+ */
+static int32_t * elements_peer1 = NULL;
+
+/**
+ * Input elements for peer2
+ */
+//char input_elements_peer2[] = 
"11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11";
+char input_elements_peer2[] = "11,11,11";
+/**
+ * Input Mask for peer 2
+ */
+//char input_mask_peer2[] = "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1";
+char input_mask_peer2[] = "1,1,1";
+/**
+ * the array of converted message IDs to send to our service
+ */
+static int32_t * elements_peer2 = NULL;
+
+/**
+ * the array of converted message IDs to send to our service
+ */
+static unsigned char * mask_peer2 = NULL;
+
+/**
+ * Data context for peer 1
+ */
+static struct PeerData peer1;
+
+/**
+ * Data context for peer 2
+ */
+static struct PeerData peer2;
+
+/**
+ * Various states during test setup
+ */
+static enum SetupState setup_state;
+
+/**
+ * Testbed operation handle
+ */
+static struct GNUNET_TESTBED_Operation *op;
+
+/**
+ * Return value of the test.
+ */
+static int ok;
+
+/**
+ * Abort Task for timeout
+ */
+static GNUNET_SCHEDULER_TaskIdentifier abort_task;
+/******************************************************************************
+ *** Static Functions                             *****************************
+ 
******************************************************************************/
+
+/**
+ * Helper function to shutdown a test peer
+ * 
+ * @param cls void* to struct PeerData of the peer to be disconnected
+ * @param tc Task Context
+ */
+static void
+do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Helper function to connect a test peer
+ * 
+ * @param cls void* to struct PeerData of the peer to be connected
+ * @param tc Task Context
+ */
+static void
+connect_peer (void *cls,
+              const struct GNUNET_SCHEDULER_TaskContext * tc);
+
+
+/**
+ * Close sockets and stop testing deamons nicely
+ */
+static void
+do_close (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+
+  if (peer1.op != NULL)
+    do_shutdown (&peer1, NULL);
+
+  if (peer2.op != NULL)
+    do_shutdown (&peer2, NULL);
+
+  if (GNUNET_SCHEDULER_NO_TASK != abort_task)
+    GNUNET_SCHEDULER_cancel (abort_task);
+
+  GNUNET_SCHEDULER_shutdown (); /* For shutting down testbed */
+}
+
+
+/**
+ * Helper function to shutdown a test peer
+ * 
+ * @param cls void* to struct PeerData of the peer to be disconnected
+ * @param tc Task Context
+ */
+static void
+do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  static int shutdown;
+  shutdown++;
+  struct PeerData* peer = (struct PeerData*) cls;
+
+  if (peer == &peer1)
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting Peer1\n\n");
+  else if (peer == &peer2)
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting Peer2\n\n");
+
+  // peer->op contains handle to the TESTBED_connect_service operation
+  // calling operation done, leads to call to vectorproduct_da
+  if (peer->op != NULL)
+    {
+      GNUNET_TESTBED_operation_done (peer->op);
+      peer->op = NULL;
+    }
+
+  if (shutdown >= 2)
+    GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_MILLISECONDS, 10), &do_close, NULL);
+}
+
+
+/**
+ * Something went wrong and timed out. Kill everything and set error flag
+ */
+static void
+do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: ABORT due to Timeout\n");
+  ok = GNUNET_SYSERR;
+  abort_task = 0;
+  do_close (cls, tc);
+}
+
+
+/**
+ * Controller event callback
+ *
+ * @param cls NULL
+ * @param event the controller event
+ */
+static void
+controller_event_cb (void *cls,
+                     const struct GNUNET_TESTBED_EventInformation *event)
+{
+  switch (event->type)
+    {
+    case GNUNET_TESTBED_ET_OPERATION_FINISHED:
+      switch (setup_state)
+        {
+        case PEER1_VECTORPRODUCT_CONNECT:
+        case PEER2_VECTORPRODUCT_CONNECT:
+          GNUNET_assert (NULL == event->details.operation_finished.emsg);
+          break;
+        default:
+          GNUNET_assert (0);
+        }
+      break;
+    default:
+      GNUNET_assert (0);
+    }
+}
+
+
+/**
+ * Callback function called for the responder peer i.e. peer1
+ * 
+ * @param cls 
+ * @param key Session key
+ * @param status Status of the message
+ */
+static void
+responder_callback (void *cls,
+                    const struct GNUNET_HashCode * key,
+                    enum GNUNET_VECTORPRODUCT_ResponseStatus status)
+{
+  if (status == GNUNET_VECTORPRODUCT_Status_Failure)
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received status 
failure\n");
+      ok = -1;
+    }
+  else if (status == GNUNET_VECTORPRODUCT_Status_InvalidResponse)
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received status 
invalid response\n");
+      ok = -1;
+    }
+  else if (GNUNET_VECTORPRODUCT_Status_Timeout == status)
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received timeout 
occured\n");
+      ok = -1;
+    }
+  else if (GNUNET_VECTORPRODUCT_Status_ServiceDisconnected == status)
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received service 
disconnected!!\n");
+      ok = 1;
+    }
+  else if (GNUNET_VECTORPRODUCT_Status_Success == status)
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "Responder Client expected response 
received!\n");
+      ok = -1;
+    }
+  else
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client status = %d!\n", (int) 
status);
+      ok = -1;
+    }
+
+  // Not shutting down this time, only for this regression test. We have 
shutdown explicitly earlier.
+  // Shutting down again is causing problems.
+
+  //  if(peer1.vh != NULL)
+  //  {
+  //    GNUNET_SCHEDULER_add_now(&do_shutdown, &peer1);
+  //  }
+  return;
+}
+
+
+/**
+ * Callback function called for the requester peer i.e. peer2
+ * 
+ * @param cls 
+ * @param key Session key
+ * @param status Status of the message
+ */
+static void
+requester_callback (void *cls,
+        const struct GNUNET_HashCode * key,
+        const struct GNUNET_PeerIdentity * peer,
+        enum GNUNET_VECTORPRODUCT_ResponseStatus status,
+        const struct GNUNET_VECTORPRODUCT_client_response *msg)
+{
+  uint32_t product_len;
+
+  if (status == GNUNET_VECTORPRODUCT_Status_Failure)
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client received status 
failure\n");
+      ok = -1;
+    }
+  else if (status == GNUNET_VECTORPRODUCT_Status_InvalidResponse)
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client received status 
invalid response\n");
+      ok = -1;
+    }
+  else if (GNUNET_VECTORPRODUCT_Status_Timeout == status)
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client timeout occured\n");
+      ok = -1;
+    }
+  else if (GNUNET_VECTORPRODUCT_Status_ServiceDisconnected == status)
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client service 
disconnected!!\n");
+      ok = 1;
+    }
+  else if (GNUNET_VECTORPRODUCT_Status_Success != status)
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "Requester Client Status = %d\n", (int) 
status);
+      ok = -1;
+    }
+  else if (GNUNET_VECTORPRODUCT_Status_Success == status)
+    {
+      product_len = ntohl (msg->product_length);
+
+      if (0 < product_len)
+        {
+          gcry_mpi_t result;
+          gcry_error_t ret = 0;
+          size_t read = 0;
+
+          ret = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, (void *) &msg[1], 
product_len, &read);
+
+          if (0 != ret)
+            {
+              GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Could not convert to mpi 
to value!\n");
+            }
+          else
+            {
+              gcry_mpi_dump (result);
+              gcry_mpi_release (result);
+            }
+          ok = -1;
+        }
+      else
+        { //currently not used, but if we get more info due to MESH we will 
need this
+          LOG (GNUNET_ERROR_TYPE_WARNING, "Error during computation of vector 
product, return code: %d\n", product_len);
+          ok = -1;
+        }
+    }
+
+  // Not shutting down this time, only for this regression test. We have 
shutdown explicitly earlier.
+  // Shutting down again is causing problems.
+
+  //  if(peer2.vh != NULL)
+  //  {
+  //    GNUNET_SCHEDULER_add_now(&do_shutdown, &peer2);
+  //  }
+  return;
+}
+
+
+static void
+requester_request (void *cls,
+                   const struct GNUNET_SCHEDULER_TaskContext * tc)
+{
+  GNUNET_assert (peer2.vh != NULL);
+
+  unsigned int i;
+  uint16_t element_count = 0;
+  uint16_t mask_length = 0;
+  char * begin = input_elements_peer2;
+  char * end;
+  int32_t element;
+  struct GNUNET_VECTORPRODUCT_QueueEntry *qe;
+  struct GNUNET_HashCode key;
+  int exit_loop = 0;
+  
+  GNUNET_CRYPTO_hash (input_key, strlen (input_key), &key);
+
+  /* Read input_elements_peer2, and put in elements_peer2 array */
+  exit_loop = 0;
+  do
+    {
+      unsigned int mcount = element_count;
+      //ignore empty rows of ,,,,,,
+      while (*begin == ',')
+        begin++;
+      // get the length of the current element and replace , with null
+      for (end = begin; *end && *end != ','; end++);
+
+      if (*end == '\0')
+        exit_loop = 1;
+
+      if (1 != sscanf (begin, "%" SCNd32, &element))
+        {
+          FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
+          ok = -1;
+          return;
+        }
+
+      GNUNET_array_append (elements_peer2, mcount, element);
+      element_count++;
+
+      begin = ++end;
+    }
+  while (!exit_loop && element_count < max_mids);
+  GNUNET_assert (elements_peer2 != NULL);
+  GNUNET_assert (element_count >= 1);
+  
+  /* Read input_mask_peer2 and read in mask_peer2 array */
+  mask_length = element_count / 8 + (element_count % 8 ? 1 : 0);
+  mask_peer2 = GNUNET_malloc ((element_count / 8) + 2);
+  GNUNET_assert (NULL != mask_peer2);
+  if (NULL != input_mask_peer2)
+    {
+      begin = input_mask_peer2;
+      unsigned short mask_count = 0;
+      exit_loop = 0;
+
+      do
+        {
+          //ignore empty rows of ,,,,,,
+          while (* begin == ',')
+            begin++;
+          // get the length of the current element and replace , with null
+          // gnunet_ascii-armor uses base32, thus we can use , as separator!
+          for (end = begin; *end && *end != ','; end++);
+
+          if (*end == '\0')
+            exit_loop = 1;
+
+          if (1 != sscanf (begin, "%" SCNd32, &element))
+            {
+              FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), 
begin);
+              ok = -1;
+              return;
+            }
+
+          GNUNET_assert (mask_count <= element_count);
+
+          if (element)
+            mask_peer2[mask_count / 8] = mask_peer2[mask_count / 8] | 1 << 
(mask_count % 8);
+
+          mask_count++;
+          begin = ++end;
+        }
+      while (!exit_loop);
+      // +1 to see if we would have more data, which would indicate 
malformed/superficial input
+      GNUNET_assert (mask_count == element_count);
+    }
+  else
+    {
+      for (i = 0; i <= mask_length; i++)
+        mask_peer2[i] = UCHAR_MAX; // all 1's
+    }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Responder peer key %s\n", 
&peer1.our_id);
+
+  qe = GNUNET_VECTORPRODUCT_request (peer2.vh,
+                                     &key,
+                                     &peer1.our_id,
+                                     element_count,
+                                     mask_length,
+                                     elements_peer2, mask_peer2,
+                                     GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_SECONDS, 10),
+                                     &requester_callback,
+                                     NULL);
+
+  if (qe == NULL)
+    {
+      FPRINTF (stderr, "%s", _ ("Could not send request to vectorproduct 
service! Exitting!"));
+      ok = -1;
+      return;
+    }
+
+  /**
+   * For regression, we shutdown the initiator peer, peer2, one second after
+   * issuing a request. Hopefully, peer1 notices that the tunnel has been
+   * been destroyed, and will shutdown cleanly.
+   */  
+  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &do_shutdown, 
&peer2);
+
+  return;
+}
+
+
+/**
+ * Function prepares the message to be sent by peer1 to its vectorproduct 
service
+ * to prepare response, and wait for a request session to be initiated by peer1
+ */
+static void
+responder_prepare_response (void *cls,
+                            const struct GNUNET_SCHEDULER_TaskContext * tc)
+{
+  GNUNET_assert (peer1.vh != NULL);
+
+  uint16_t element_count = 0;
+  char * begin = input_elements_peer1;
+  char * end;
+  int32_t element;
+
+  struct GNUNET_VECTORPRODUCT_QueueEntry *qe;
+
+  struct GNUNET_HashCode key;
+  GNUNET_CRYPTO_hash (input_key, strlen (input_key), &key);
+
+  int exit_loop = 0;
+  /* Read input_elements_peer1, and put in elements_peer1 array */
+  do
+    {
+      unsigned int mcount = element_count;
+      //ignore empty rows of ,,,,,,
+      while (*begin == ',')
+        begin++;
+      // get the length of the current element and replace , with null
+      for (end = begin; *end && *end != ','; end++);
+
+      if (*end == '\0')
+        exit_loop = 1;
+
+      if (1 != sscanf (begin, "%" SCNd32, &element))
+        {
+          FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
+          ok = -1;
+          return;
+        }
+
+      GNUNET_array_append (elements_peer1, mcount, element);
+      element_count++;
+
+      begin = ++end;
+    }
+  while (!exit_loop && element_count < max_mids);
+
+  GNUNET_assert (elements_peer1 != NULL);
+  GNUNET_assert (element_count >= 1);
+
+  qe = GNUNET_VECTORPRODUCT_prepare_response (peer1.vh,
+                                              &key,
+                                              element_count,
+                                              elements_peer1,
+                                              GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_SECONDS, 10),
+                                              &responder_callback,
+                                              NULL);
+
+  if (qe == NULL)
+    {
+      FPRINTF (stderr, "%s", _ ("Could not send request to vectorproduct 
service! Exitting!"));
+      ok = -1;
+      return;
+    }
+
+  // connect the second peer
+  setup_state = PEER2_VECTORPRODUCT_CONNECT;
+  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_SECONDS, 1), &connect_peer, &peer2);
+
+  // while the service is waiting for a matching request, disconnect the test 
client
+  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &do_shutdown, 
&peer1);
+
+  return;
+}
+
+
+/**
+ * Adapter function called to destroy a connection to
+ * a service. This function is called when GNUNET_TESTBED_operation_done is
+ * called for peer->op, which holds the handle for 
GNUNET_TESTBED_service_connect
+ * operation.
+ * 
+ * @param cls closure
+ * @param op_result service handle returned from the connect adapter
+ */
+static void
+vectorproduct_da (void *cls, void *op_result)
+{
+  struct PeerData* peer = (struct PeerData*) cls;
+
+  GNUNET_VECTORPRODUCT_disconnect (peer->vh);
+  peer->vh = NULL;
+  return;
+}
+
+
+/**
+ * Adapter function called to establish a connection to
+ * a service. This function is called to by GNUNET_TESTBED_service_connect.
+ * 
+ * @param cls closure
+ * @param cfg configuration of the peer to connect to; will be available until
+ *          GNUNET_TESTBED_operation_done() is called on the operation returned
+ *          from GNUNET_TESTBED_service_connect()
+ * @return service handle to return in 'op_result', NULL on error
+ */
+static void *
+vectorproduct_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  struct PeerData *p = cls;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", (&peer1 == 
p) ? 1 : 2,
+              GNUNET_i2s (&p->our_id));
+
+  switch (setup_state)
+    {
+    case PEER1_VECTORPRODUCT_CONNECT:
+      peer1.vh = GNUNET_VECTORPRODUCT_connect (cfg);
+
+      if (peer1.vh != NULL)
+        {
+          /* prepare_response from peer1 */
+          GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, 
&responder_prepare_response, NULL);
+        }
+      else
+        {
+          ok = -1;
+          return NULL;
+        }
+
+      return peer1.vh;
+
+    case PEER2_VECTORPRODUCT_CONNECT:
+      /* Actually connect peer 2 to vectorproduct service */
+      peer2.vh = GNUNET_VECTORPRODUCT_connect (cfg);
+
+      if (peer2.vh != NULL)
+        {
+          /* initiate request from peer2 */
+          GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, 
&requester_request, NULL);
+        }
+      else
+        {
+          ok = -1;
+          return NULL;
+        }
+
+      return peer2.vh;
+    default:
+      GNUNET_assert (0);
+    }
+}
+
+
+/**
+ * Helper function to connect a test peer
+ * 
+ * @param cls void* to struct PeerData of the peer to be connected
+ * @param tc Task Context
+ */
+static void
+connect_peer (void *cls,
+              const struct GNUNET_SCHEDULER_TaskContext * tc)
+{
+  struct PeerData *peer = cls;
+
+  peer->op = GNUNET_TESTBED_service_connect (peer, peer->peer, "vectorproduct",
+                                             NULL, NULL, vectorproduct_ca,
+                                             vectorproduct_da, peer);
+
+}
+
+
+/**
+ * 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
+peerinfo_cb (void *cb_cls, struct GNUNET_TESTBED_Operation *op_,
+             const struct GNUNET_TESTBED_PeerInformation *pinfo,
+             const char *emsg)
+{
+  GNUNET_assert (NULL == emsg);
+  GNUNET_assert (op == op_);
+  
+  switch (setup_state)
+    {
+    case PEER1_GET_IDENTITY:
+      {
+        memcpy (&peer1.our_id, pinfo->result.id,
+                sizeof (struct GNUNET_PeerIdentity));
+        GNUNET_TESTBED_operation_done (op);
+
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 1 id: %s\n", GNUNET_i2s_full
+                    (&peer1.our_id));
+
+        /* Request for peer id of peer 2*/
+        setup_state = PEER2_GET_IDENTITY;
+        op = GNUNET_TESTBED_peer_get_information (peer2.peer,
+                                                  GNUNET_TESTBED_PIT_IDENTITY,
+                                                  &peerinfo_cb, NULL);
+      }
+      break;
+    case PEER2_GET_IDENTITY:
+      {
+        memcpy (&peer2.our_id, pinfo->result.id,
+                sizeof (struct GNUNET_PeerIdentity));
+        GNUNET_TESTBED_operation_done (op);
+
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 2 id: %s\n", GNUNET_i2s_full
+                    (&peer2.our_id));
+
+        /* Connect peer 1 to vectorproduct service */
+        setup_state = PEER1_VECTORPRODUCT_CONNECT;
+        GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, 
&connect_peer, &peer1);
+      }
+      break;
+    default:
+      GNUNET_assert (0);
+    }
+}
+
+
+/**
+ * Signature of a main function for a testcase.
+ *
+ * @param cls closure
+ * @param num_peers number of peers in 'peers'
+ * @param peers handle to peers run in the testbed
+ */
+static void
+test_master (void *cls, unsigned int num_peers,
+             struct GNUNET_TESTBED_Peer **peers)
+{
+  GNUNET_assert (NULL != peers);
+  GNUNET_assert (NULL != peers[0]);
+  GNUNET_assert (NULL != peers[1]);
+  peer1.peer = peers[0];
+  peer2.peer = peers[1];
+
+  /* Get the peer identity and configuration of peer 1 */
+  setup_state = PEER1_GET_IDENTITY;
+  op = GNUNET_TESTBED_peer_get_information (peer1.peer,
+                                            GNUNET_TESTBED_PIT_IDENTITY,
+                                            &peerinfo_cb, NULL);
+
+  abort_task =
+          GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+                                        (GNUNET_TIME_UNIT_SECONDS, 20), 
&do_abort,
+                                        NULL);
+}
+
+
+/**
+ * Main function
+ */
+int
+main (int argc, char **argv)
+{
+  uint64_t event_mask;
+
+  ok = GNUNET_NO;
+  event_mask = 0;
+  event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
+  max_mids = (GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct 
GNUNET_MessageHeader))
+          / sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1;
+
+  (void) GNUNET_TESTBED_test_run ("test_vectorproduct_api_regression",
+                                  "test_vectorproduct_api_data.conf",
+                                  NUM_PEERS, event_mask, &controller_event_cb,
+                                  NULL,
+                                  &test_master, NULL);
+
+  if (GNUNET_SYSERR == ok)
+    return 1;
+  return 0;
+}
+
+

Added: gnunet/src/vectorproduct/test_vectorproduct_api_regression2.c
===================================================================
--- gnunet/src/vectorproduct/test_vectorproduct_api_regression2.c               
                (rev 0)
+++ gnunet/src/vectorproduct/test_vectorproduct_api_regression2.c       
2013-08-22 13:41:49 UTC (rev 28794)
@@ -0,0 +1,931 @@
+/*
+     This file is part of GNUnet.
+     (C) 2013 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 vectorproduct/test_vectorproduct_api_regression2.c
+ * @brief Regression test, destroys requester service before receiving response
+ *        responder service
+ * @author Gaurav Kukreja
+ * @author Christian Fuchs
+ */
+
+#include <string.h>
+
+#include <inttypes.h>
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_testbed_service.h"
+#include "gnunet_common.h"
+#include "gnunet_vectorproduct_service.h"
+#include "gnunet_protocols.h"
+
+#define LOG(kind,...) GNUNET_log_from (kind, 
"test-vectorproduct-api-regression2",__VA_ARGS__)
+#define NUM_PEERS 2
+
+/**
+ * Structure for holding peer's sockets and IO Handles
+ */
+struct PeerData
+{
+  /**
+   * Handle to testbed peer
+   */
+  struct GNUNET_TESTBED_Peer *peer;
+
+  /**
+   * The service connect operation to stream
+   */
+  struct GNUNET_TESTBED_Operation *op;
+
+  /**
+   * Our Peer id
+   */
+  struct GNUNET_PeerIdentity our_id;
+
+  /**
+   * Pointer to Vector Product Handle
+   */
+  struct GNUNET_VECTORPRODUCT_Handle *vh;
+};
+
+/**
+ * Different states in test setup
+ */
+enum SetupState
+{
+  /**
+   * Get the identity of peer 1
+   */
+  PEER1_GET_IDENTITY,
+
+  /**
+   * Get the identity of peer 2
+   */
+  PEER2_GET_IDENTITY,
+
+  /**
+   * Connect to stream service of peer 1
+   */
+  PEER1_VECTORPRODUCT_CONNECT,
+
+  /**
+   * Connect to stream service of peer 2
+   */
+  PEER2_VECTORPRODUCT_CONNECT
+
+};
+
+/******************************************************************************
+ *** Global Variables                            *****************************
+ 
******************************************************************************/
+
+/**
+ * Maximum allowed message-ids we can check in one go (with one GNUNET_message)
+ */
+static unsigned int max_mids;
+
+/**
+ * Session Key used by both the test peers
+ */
+char input_key[103] = 
"helloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhe";
+
+/**
+ * Input elements for peer1
+ */
+char input_elements_peer1[] = 
"11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11";
+//char input_elements_peer1[] = "11,11,11";
+
+/**
+ * Input Mask for peer 1
+ */
+char input_mask_peer1[] = "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1";
+//char input_mask_peer1[] = "1,1,1";
+
+/**
+ * the array of converted message IDs to send to our service
+ */
+static int32_t * elements_peer1 = NULL;
+
+/**
+ * the array of converted message IDs to send to our service
+ */
+static unsigned char * mask_peer1 = NULL;
+
+/**
+ * Number of elements
+ */
+uint16_t element_count_peer1 = 0;
+
+/**
+ * Input elements for peer2
+ */
+char input_elements_peer2[] = 
"11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11";
+//char input_elements_peer2[] = "11,11,11";
+
+/**
+ * Input Mask for peer 2
+ */
+char input_mask_peer2[] = "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1";
+//char input_mask_peer2[] = "1,1,1";
+
+/**
+ * the array of converted message IDs to send to our service
+ */
+static int32_t * elements_peer2 = NULL;
+
+/**
+ * the array of converted message IDs to send to our service
+ */
+static unsigned char * mask_peer2 = NULL;
+
+/**
+ * Number of elements
+ */
+uint16_t element_count_peer2 = 0;
+
+/**
+ * Data context for peer 1
+ */
+static struct PeerData peer1;
+
+/**
+ * Data context for peer 2
+ */
+static struct PeerData peer2;
+
+/**
+ * Various states during test setup
+ */
+static enum SetupState setup_state;
+
+/**
+ * Testbed operation handle
+ */
+static struct GNUNET_TESTBED_Operation *op;
+
+static int ok;
+
+static int responder_ok;
+
+static int requester_ok;
+
+static GNUNET_SCHEDULER_TaskIdentifier abort_task;
+/******************************************************************************
+ *** Static Functions                             *****************************
+ 
******************************************************************************/
+
+static void
+do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Close sockets and stop testing deamons nicely
+ */
+static void
+do_close (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  static int closed;
+
+  if (peer1.op != NULL)
+    {
+      do_shutdown (&peer1, NULL);
+    }
+
+  if (peer2.op != NULL)
+    {
+      do_shutdown (&peer2, NULL);
+    }
+
+  if (GNUNET_SCHEDULER_NO_TASK != abort_task)
+    {
+      GNUNET_SCHEDULER_cancel (abort_task);
+      abort_task = GNUNET_SCHEDULER_NO_TASK;
+      GNUNET_SCHEDULER_shutdown (); /* For shutting down testbed */
+    }
+
+  if (!closed)
+    {
+      closed++;
+      GNUNET_SCHEDULER_shutdown (); /* For shutting down testbed */
+    }
+}
+
+/**
+ * Shutdown a peer
+ * 
+ * @param cls closure is a pointer to the struct PeerData of the peer to be 
disconnected
+ * @param tc Task Context
+ */
+static void
+do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  static int shutdown;
+  shutdown++;
+  struct PeerData* peer = (struct PeerData*) cls;
+
+  // peer->op contains handle to the TESTBED_connect_service operation
+  // calling operation done, leads to call to vectorproduct_da
+  if (peer->op != NULL)
+    {
+      if (peer == &peer1)
+        LOG (GNUNET_ERROR_TYPE_INFO, "Disconnecting Peer1\n\n");
+      else if (peer == &peer2)
+        LOG (GNUNET_ERROR_TYPE_INFO, "Disconnecting Peer2\n\n");
+
+      GNUNET_TESTBED_operation_done (peer->op);
+      peer->op = NULL;
+    }
+
+  if (peer1.op == NULL && peer2.op == NULL)
+    GNUNET_SCHEDULER_add_now (&do_close, NULL);
+}
+
+
+/**
+ * Something went wrong and timed out. Kill everything and set error flag
+ */
+static void
+do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: ABORT due to Timeout\n");
+  ok = GNUNET_SYSERR;
+  abort_task = GNUNET_SCHEDULER_NO_TASK;
+  GNUNET_SCHEDULER_add_now (&do_shutdown, &peer1);
+  GNUNET_SCHEDULER_add_now (&do_shutdown, &peer2);
+}
+
+
+/**
+ * Controller event callback
+ *
+ * @param cls NULL
+ * @param event the controller event
+ */
+static void
+controller_event_cb (void *cls,
+                     const struct GNUNET_TESTBED_EventInformation *event)
+{
+  switch (event->type)
+    {
+    case GNUNET_TESTBED_ET_OPERATION_FINISHED:
+      switch (setup_state)
+        {
+        case PEER1_VECTORPRODUCT_CONNECT:
+        case PEER2_VECTORPRODUCT_CONNECT:
+          GNUNET_assert (NULL == event->details.operation_finished.emsg);
+          break;
+        default:
+          GNUNET_assert (0);
+        }
+      break;
+    default:
+      GNUNET_assert (0);
+    }
+}
+
+
+static void
+responder_callback (void *cls,
+                    const struct GNUNET_HashCode * key,
+                    enum GNUNET_VECTORPRODUCT_ResponseStatus status)
+{
+  if (status == GNUNET_VECTORPRODUCT_Status_Failure)
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received status 
failure\n");
+      responder_ok = -1;
+    }
+  else if (status == GNUNET_VECTORPRODUCT_Status_InvalidResponse)
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received status 
invalid response\n");
+      responder_ok = -1;
+    }
+  else if (GNUNET_VECTORPRODUCT_Status_Timeout == status)
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received timeout 
occured\n");
+      // In this regression test, requester is supposed to fail due to timeout
+      // therefore responder_ok is set to 1, to make regression test pass
+      responder_ok = 1;
+    }
+  else if (GNUNET_VECTORPRODUCT_Status_ServiceDisconnected == status)
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received service 
disconnected!!\n");
+      responder_ok = -1;
+    }
+  else if (GNUNET_VECTORPRODUCT_Status_Success == status)
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "Responder Client expected response 
received!\n");
+      responder_ok = 1;
+    }
+  else
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client status = %d!\n", (int) 
status);
+      responder_ok = -1;
+    }
+  // TODO : Responder Session Complete. Shutdown Test Cleanly!!!
+  //do_shutdown(&peer1, NULL);
+  GNUNET_SCHEDULER_add_now (&do_shutdown, &peer1);
+  return;
+}
+
+
+static void
+requester_callback (void *cls,
+                    const struct GNUNET_HashCode * key,
+                    const struct GNUNET_PeerIdentity * peer,
+                    enum GNUNET_VECTORPRODUCT_ResponseStatus status,
+                    uint16_t size, struct GNUNET_VECTORPRODUCT_client_response 
*msg,
+                    uint16_t type)
+{
+  uint32_t product_len;
+
+  if (status == GNUNET_VECTORPRODUCT_Status_Failure)
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client received status 
failure\n");
+      // In this regression test, requester is supposed to receive status 
failure
+      // therefore requester_ok is set to 1, to make regression test pass
+      requester_ok = 1;
+    }
+  else if (status == GNUNET_VECTORPRODUCT_Status_InvalidResponse)
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client received status 
invalid response\n");
+      requester_ok = -1;
+    }
+  else if (GNUNET_VECTORPRODUCT_Status_Timeout == status)
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client timeout occured\n");
+      requester_ok = -1;
+    }
+  else if (GNUNET_VECTORPRODUCT_Status_ServiceDisconnected == status)
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client service 
disconnected!!\n");
+      requester_ok = -1;
+    }
+  else if (GNUNET_VECTORPRODUCT_Status_Success != status)
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client Status = %d\n", (int) 
status);
+      requester_ok = -1;
+    }
+  else if (GNUNET_VECTORPRODUCT_Status_Success == status)
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "Requester Client expected response 
received!\n");
+
+      product_len = ntohl (msg->product_length);
+
+      if (0 < product_len)
+        {
+          gcry_mpi_t result;
+          gcry_error_t ret = 0;
+          size_t read = 0;
+
+          ret = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, (void *) &msg[1], 
product_len, &read);
+
+          if (0 != ret)
+            {
+              GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not convert to mpi 
to value!\n");
+              ok = -1;
+            }
+          else
+            {
+              uint16_t i = 0;
+
+              // calculate expected product 
+              gcry_mpi_t expected_result;
+              gcry_mpi_t v1;
+              gcry_mpi_t v2;
+              gcry_mpi_t v1_v2_prod;
+
+              expected_result = gcry_mpi_new (0);
+
+              for (i = 0; i < element_count_peer1; i++)
+                {
+                  uint32_t value;
+                  v1_v2_prod = gcry_mpi_new (0);
+
+                  // long to gcry_mpi_t
+                  value = elements_peer1[i] >= 0 ? elements_peer1[i] : 
-elements_peer1[i];
+                  if (elements_peer1[i] < 0)
+                    {
+                      v1 = gcry_mpi_new (0);
+                      gcry_mpi_sub_ui (v1, v1, value);
+                    }
+                  else
+                    v1 = gcry_mpi_set_ui (NULL, value);
+
+                  // long to gcry_mpi_t
+                  value = elements_peer2[i] >= 0 ? elements_peer2[i] : 
-elements_peer2[i];
+                  if (elements_peer2[i] < 0)
+                    {
+                      v2 = gcry_mpi_new (0);
+                      gcry_mpi_sub_ui (v2, v2, value);
+                    }
+                  else
+                    v2 = gcry_mpi_set_ui (NULL, value);
+
+                  gcry_mpi_mul (v1_v2_prod, v1, v2);
+                  gcry_mpi_add (expected_result, expected_result, v1_v2_prod);
+
+                  gcry_mpi_release (v1);
+                  gcry_mpi_release (v2);
+                  gcry_mpi_release (v1_v2_prod);
+
+                }
+
+              // compare the result
+              if (!gcry_mpi_cmp (expected_result, result))
+                {
+                  LOG (GNUNET_ERROR_TYPE_DEBUG, "Scalar Product matches 
expected Result!!\n");
+                  requester_ok = 1;
+                }
+              else
+                {
+                  LOG (GNUNET_ERROR_TYPE_WARNING, "Scalar Product DOES NOT 
match expected Result!!\n");
+                  requester_ok = -1;
+                }
+              gcry_mpi_release (result);
+              gcry_mpi_release (expected_result);
+            }
+        }
+      else
+        { //currently not used, but if we get more info due to MESH we will 
need this
+          LOG (GNUNET_ERROR_TYPE_WARNING, "Error during computation of vector 
product, return code: %d\n", product_len);
+          requester_ok = -1;
+        }
+    }
+
+  //do_shutdown(&peer2, NULL);
+  GNUNET_SCHEDULER_add_now (&do_shutdown, &peer2);
+  return;
+}
+
+
+static struct GNUNET_VECTORPRODUCT_QueueEntry *
+requester_request ()
+{
+  GNUNET_assert (peer2.vh != NULL);
+
+  unsigned int i;
+  //uint16_t element_count_peer2 = 0;
+  uint16_t mask_length = 0;
+  char * begin = input_elements_peer2;
+  char * end;
+  int32_t element;
+
+  struct GNUNET_VECTORPRODUCT_QueueEntry *qe;
+
+  struct GNUNET_HashCode key;
+  GNUNET_CRYPTO_hash (input_key, strlen (input_key), &key);
+
+  int exit_loop = 0;
+  /* Read input_elements_peer2, and put in elements_peer2 array */
+  do
+    {
+      unsigned int mcount = element_count_peer2;
+      //ignore empty rows of ,,,,,,
+      while (*begin == ',')
+        begin++;
+      // get the length of the current element and replace , with null
+      for (end = begin; *end && *end != ','; end++);
+
+      if (*end == '\0')
+        exit_loop = 1;
+
+      if (1 != sscanf (begin, "%" SCNd32, &element))
+        {
+          FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
+          ok = -1;
+          return NULL;
+        }
+
+      GNUNET_array_append (elements_peer2, mcount, element);
+      element_count_peer2++;
+
+      begin = ++end;
+    }
+  while (!exit_loop && element_count_peer2 < max_mids);
+
+  GNUNET_assert (elements_peer2 != NULL);
+  GNUNET_assert (element_count_peer2 >= 1);
+  mask_length = element_count_peer2 / 8 + (element_count_peer2 % 8 ? 1 : 0);
+  mask_peer2 = GNUNET_malloc ((element_count_peer2 / 8) + 2);
+  GNUNET_assert (NULL != mask_peer2);
+
+  /* Read input_mask_peer2 and read in mask_peer2 array */
+  if (NULL != input_mask_peer2)
+    {
+      begin = input_mask_peer2;
+      unsigned short mask_count = 0;
+      int exit_loop = 0;
+
+      do
+        {
+          //ignore empty rows of ,,,,,,
+          while (* begin == ',')
+            begin++;
+          // get the length of the current element and replace , with null
+          // gnunet_ascii-armor uses base32, thus we can use , as separator!
+          for (end = begin; *end && *end != ','; end++);
+
+          if (*end == '\0')
+            exit_loop = 1;
+
+          if (1 != sscanf (begin, "%" SCNd32, &element))
+            {
+              FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), 
begin);
+              ok = -1;
+              return NULL;
+            }
+
+          GNUNET_assert (mask_count <= element_count_peer2);
+
+          if (element)
+            mask_peer2[mask_count / 8] = mask_peer2[mask_count / 8] | 1 << 
(mask_count % 8);
+
+          mask_count++;
+          begin = ++end;
+        }
+      while (!exit_loop);
+      // +1 to see if we would have more data, which would indicate 
malformed/superficial input
+      GNUNET_assert (mask_count == element_count_peer2);
+    }
+  else
+    {
+      for (i = 0; i <= mask_length; i++)
+        mask_peer2[i] = UCHAR_MAX; // all 1's
+    }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Responder peer key %s\n", 
&peer1.our_id);
+
+  // TODO : Create the mask array
+  qe = GNUNET_VECTORPRODUCT_request (peer2.vh,
+                                     &key,
+                                     &peer1.our_id,
+                                     element_count_peer2,
+                                     mask_length,
+                                     elements_peer2, mask_peer2,
+                                     GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_SECONDS, 10),
+                                     &requester_callback,
+                                     NULL);
+
+  if (qe == NULL)
+    {
+      FPRINTF (stderr, "%s", _ ("Could not send request to vectorproduct 
service! Exitting!"));
+      ok = -1;
+      return NULL;
+    }
+
+  return qe;
+}
+
+
+/**
+ * Function prepares the message to be sent by peer1 to its vectorproduct 
service
+ * to prepare response, and wait for a request session to be initiated by peer1
+ */
+static struct GNUNET_VECTORPRODUCT_QueueEntry *
+responder_prepare_response ()
+{
+  GNUNET_assert (peer1.vh != NULL);
+
+  unsigned int i;
+  //uint16_t element_count_peer1 = 0;
+  char * begin = input_elements_peer1;
+  char * end;
+  int32_t element;
+
+  struct GNUNET_VECTORPRODUCT_QueueEntry *qe;
+
+  struct GNUNET_HashCode key;
+  GNUNET_CRYPTO_hash (input_key, strlen (input_key), &key);
+
+  int exit_loop = 0;
+  /* Read input_elements_peer1, and put in elements_peer1 array */
+  do
+    {
+      unsigned int mcount = element_count_peer1;
+      //ignore empty rows of ,,,,,,
+      while (*begin == ',')
+        begin++;
+      // get the length of the current element and replace , with null
+      for (end = begin; *end && *end != ','; end++);
+
+      if (*end == '\0')
+        exit_loop = 1;
+
+      if (*end == ',')
+        *end = '\0';
+
+      if (1 != sscanf (begin, "%" SCNd32, &element))
+        {
+          FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
+          ok = -1;
+          return NULL;
+        }
+
+      GNUNET_array_append (elements_peer1, mcount, element);
+      element_count_peer1++;
+
+      begin = ++end;
+    }
+  while (!exit_loop && element_count_peer1 < max_mids);
+
+  GNUNET_assert (elements_peer1 != NULL);
+  GNUNET_assert (element_count_peer1 >= 1);
+
+  qe = GNUNET_VECTORPRODUCT_prepare_response (peer1.vh,
+                                              &key,
+                                              element_count_peer1,
+                                              elements_peer1,
+                                              GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_SECONDS, 10),
+                                              &responder_callback,
+                                              NULL);
+
+  if (qe == NULL)
+    {
+      FPRINTF (stderr, "%s", _ ("Could not send request to vectorproduct 
service! Exitting!"));
+      ok = -1;
+      return NULL;
+    }
+  return qe;
+}
+
+
+/**
+ * Scheduler task to initiate requester client
+ * 
+ * @param cls void* to struct PeerData
+ * @param tc Task Context
+ */
+static void
+request_task (void *cls,
+              const struct GNUNET_SCHEDULER_TaskContext
+              * tc)
+{
+  struct PeerData * peer = cls;
+
+  requester_request ();
+  return;
+}
+
+
+/**
+ * Scheduler task to initiate responder client
+ * 
+ * @param cls void* to struct PeerData
+ * @param tc Task Context
+ */
+static void
+prepare_response_task (void *cls,
+                       const struct GNUNET_SCHEDULER_TaskContext
+                       * tc)
+{
+  struct PeerData * peer = cls;
+
+  responder_prepare_response ();
+  return;
+}
+
+
+static void
+peer_stop_callback (void *cls,
+                    const char *emsg)
+{
+  GNUNET_TESTBED_peer_destroy (peer2.peer);
+}
+
+/**
+ * Destroys Peer2 i.e. the initiator peer (Alice) This function is scheduled to
+ * run a few milliseconds after the request has been sent to the Responding 
Peer (Bob).
+ * This function tries to emulate a crash of Peer2.
+ * 
+ * @param cls Not used
+ * @param tc Task Context - Not used
+ */
+static void
+destroy_server (void *cls,
+                const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  LOG (GNUNET_ERROR_TYPE_INFO, "\n***\nKilling the Requesting Client, 
hopefully before it receives response\n***\n");
+  do_shutdown (&peer2, NULL);
+  GNUNET_TESTBED_peer_stop (peer2.peer, &peer_stop_callback, NULL);
+}
+
+
+/**
+ * Adapter function called to destroy a connection to
+ * a service. This function is called when GNUNET_TESTBED_operation_done is
+ * called for peer->op, which holds the handle for 
GNUNET_TESTBED_service_connect
+ * operation.
+ * 
+ * @param cls closure
+ * @param op_result service handle returned from the connect adapter
+ */
+static void
+vectorproduct_da (void *cls, void *op_result)
+{
+  struct PeerData* peer = (struct PeerData*) cls;
+
+  GNUNET_VECTORPRODUCT_disconnect (peer->vh);
+  return;
+}
+
+
+/**
+ * Adapter function called to establish a connection to
+ * a service. This function is called to by GNUNET_TESTBED_service_connect.
+ * 
+ * @param cls closure
+ * @param cfg configuration of the peer to connect to; will be available until
+ *          GNUNET_TESTBED_operation_done() is called on the operation returned
+ *          from GNUNET_TESTBED_service_connect()
+ * @return service handle to return in 'op_result', NULL on error
+ */
+static void *
+vectorproduct_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  struct PeerData *p = cls;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", (&peer1 == 
p) ? 1 : 2,
+              GNUNET_i2s (&p->our_id));
+
+  switch (setup_state)
+    {
+    case PEER1_VECTORPRODUCT_CONNECT:
+      /* Connect peer 2 to vectorproduct service */
+      /* The connect adapter vectorproduct_ca will be called to perform the 
actual connection */
+      {
+        peer2.op = GNUNET_TESTBED_service_connect (&peer2, peer2.peer, 
"vectorproduct",
+                                                   NULL, NULL, 
vectorproduct_ca,
+                                                   vectorproduct_da, &peer2);
+        setup_state = PEER2_VECTORPRODUCT_CONNECT;
+      }
+
+      /* Actually connect peer 1 to vectorproduct service */
+      peer1.vh = GNUNET_VECTORPRODUCT_connect (cfg);
+      return peer1.vh;
+
+    case PEER2_VECTORPRODUCT_CONNECT:
+      /* Actually connect peer 2 to vectorproduct service */
+      peer2.vh = GNUNET_VECTORPRODUCT_connect (cfg);
+
+
+      if (peer1.vh != NULL && peer2.vh != NULL)
+        {
+          GNUNET_SCHEDULER_add_now (&prepare_response_task, &peer1);
+          GNUNET_SCHEDULER_add_now (&request_task, &peer2);
+          GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_MILLISECONDS, 6),
+                                        &destroy_server, NULL);
+        }
+      else
+        {
+          // TODO : Handle error. One of the peers is not connected. Cleanly 
shutdown
+          ok = -1;
+          return NULL;
+        }
+      return peer2.vh;
+    default:
+      GNUNET_assert (0);
+    }
+}
+
+
+/**
+ * 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
+peerinfo_cb (void *cb_cls, struct GNUNET_TESTBED_Operation *op_,
+             const struct GNUNET_TESTBED_PeerInformation *pinfo,
+             const char *emsg)
+{
+  GNUNET_assert (NULL == emsg);
+  GNUNET_assert (op == op_);
+  switch (setup_state)
+    {
+    case PEER1_GET_IDENTITY:
+      {
+        memcpy (&peer1.our_id, pinfo->result.id,
+                sizeof (struct GNUNET_PeerIdentity));
+        GNUNET_TESTBED_operation_done (op);
+
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 1 id: %s\n", GNUNET_i2s_full
+                    (&peer1.our_id));
+
+        /* Request for peer id of peer 2*/
+        op = GNUNET_TESTBED_peer_get_information (peer2.peer,
+                                                  GNUNET_TESTBED_PIT_IDENTITY,
+                                                  &peerinfo_cb, NULL);
+        setup_state = PEER2_GET_IDENTITY;
+      }
+      break;
+    case PEER2_GET_IDENTITY:
+      {
+        memcpy (&peer2.our_id, pinfo->result.id,
+                sizeof (struct GNUNET_PeerIdentity));
+        GNUNET_TESTBED_operation_done (op);
+
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 2 id: %s\n", GNUNET_i2s_full
+                    (&peer2.our_id));
+
+        /* Connect peer 1 to vectorproduct service */
+        /* The connect adapter vectorproduct_ca will be called to perform the 
actual connection */
+        peer1.op = GNUNET_TESTBED_service_connect (&peer1, peer1.peer, 
"vectorproduct",
+                                                   NULL, NULL, 
vectorproduct_ca,
+                                                   vectorproduct_da, &peer1);
+        setup_state = PEER1_VECTORPRODUCT_CONNECT;
+      }
+      break;
+    default:
+      GNUNET_assert (0);
+    }
+}
+
+
+/**
+ * Signature of a main function for a testcase.
+ *
+ * @param cls closure
+ * @param num_peers number of peers in 'peers'
+ * @param peers handle to peers run in the testbed
+ */
+static void
+test_master (void *cls, unsigned int num_peers,
+             struct GNUNET_TESTBED_Peer **peers)
+{
+  GNUNET_assert (NULL != peers);
+  GNUNET_assert (NULL != peers[0]);
+  GNUNET_assert (NULL != peers[1]);
+  peer1.peer = peers[0];
+  peer2.peer = peers[1];
+  /* Get the peer identity and configuration of peer 1 */
+  op = GNUNET_TESTBED_peer_get_information (peer1.peer,
+                                            GNUNET_TESTBED_PIT_IDENTITY,
+                                            &peerinfo_cb, NULL);
+  setup_state = PEER1_GET_IDENTITY;
+  abort_task =
+          GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+                                        (GNUNET_TIME_UNIT_SECONDS, 20), 
&do_abort,
+                                        NULL);
+}
+
+
+/**
+ * Main function
+ */
+int
+main (int argc, char **argv)
+{
+  uint64_t event_mask;
+
+  ok = GNUNET_NO;
+  event_mask = 0;
+  event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
+  max_mids = (GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct 
GNUNET_MessageHeader))
+          / sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1;
+
+  (void) GNUNET_TESTBED_test_run ("test_vectorproduct_api_regression2",
+                                  "test_vectorproduct_api_data.conf",
+                                  NUM_PEERS, event_mask, &controller_event_cb,
+                                  NULL,
+                                  &test_master, NULL);
+  if (GNUNET_SYSERR == ok)
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Test failing due to some error before 
calling API for request or prepare_response\n");
+      return 1;
+    }
+  else if (GNUNET_SYSERR == responder_ok)
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Test failing due to some error in 
response for responding_client\n");
+      return 1;
+    }
+  else if (GNUNET_SYSERR == requester_ok)
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR, "Test failing due to some error in 
response for requesting client\n");
+      return 1;
+    }
+  else
+    return 0;
+}
+
+

Added: gnunet/src/vectorproduct/vectorproduct.conf.in
===================================================================
--- gnunet/src/vectorproduct/vectorproduct.conf.in                              
(rev 0)
+++ gnunet/src/vectorproduct/vectorproduct.conf.in      2013-08-22 13:41:49 UTC 
(rev 28794)
@@ -0,0 +1,7 @@
+[vectorproduct]
+BINARY = gnunet-service-vectorproduct
+UNIXPATH = /tmp/gnunet-service-vectorproduct.sock
+HOME = $SERVICEHOME
+# PORT = 2106
address@hidden@ PORT = 2087
+

Added: gnunet/src/vectorproduct/vectorproduct_api.c
===================================================================
--- gnunet/src/vectorproduct/vectorproduct_api.c                                
(rev 0)
+++ gnunet/src/vectorproduct/vectorproduct_api.c        2013-08-22 13:41:49 UTC 
(rev 28794)
@@ -0,0 +1,715 @@
+/*
+     This file is part of GNUnet.
+     (C) 2013 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 vectorproduct/vectorproduct_api.c
+ * @brief API for the vectorproduct
+ * @author Christian Fuchs
+ * @author Gaurav Kukreja
+ * 
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_vectorproduct_service.h"
+#include "gnunet_protocols.h"
+
+#define LOG(kind,...) GNUNET_log_from (kind, "vectorproduct-api",__VA_ARGS__)
+
+/**************************************************************
+ ***  Datatype Declarations                          **********
+ **************************************************************/
+
+/**
+ * Entry in the request queue per client
+ */
+struct GNUNET_VECTORPRODUCT_QueueEntry
+{
+  /**
+   * This is a linked list.
+   */
+  struct GNUNET_VECTORPRODUCT_QueueEntry *next;
+
+  /**
+   * This is a linked list.
+   */
+  struct GNUNET_VECTORPRODUCT_QueueEntry *prev;
+
+  /**
+   * Handle to the master context.
+   */
+  struct GNUNET_VECTORPRODUCT_Handle *h;
+
+  /**
+   * Size of the message
+   */
+  uint16_t message_size;
+
+  /**
+   * Message to be sent to the vectorproduct service
+   */
+  struct GNUNET_VECTORPRODUCT_client_request* msg;
+
+  union
+  {
+    /**
+     * Function to call after transmission of the request.
+     */
+    GNUNET_VECTORPRODUCT_ContinuationWithStatus cont_status;
+
+    /**
+     * Function to call after transmission of the request.
+     */
+    GNUNET_VECTORPRODUCT_DatumProcessor cont_datum;
+  };
+
+  /**
+   * Closure for 'cont'.
+   */
+  void *cont_cls;
+
+  /**
+   * Has this message been transmitted to the service?
+   * Only ever GNUNET_YES for the head of the queue.
+   * Note that the overall struct should end at a
+   * multiple of 64 bits.
+   */
+  int16_t was_transmitted;
+
+  /**
+   * Timeout for the current operation.
+   */
+  struct GNUNET_TIME_Absolute timeout;
+
+  /**
+   * Task for timeout signaling.
+   */
+  GNUNET_SCHEDULER_TaskIdentifier timeout_task;
+
+  /**
+   * Response Processor for response from the service. This function calls the
+   * continuation function provided by the client.
+   */
+  GNUNET_VECTORPRODUCT_ResponseMessageHandler response_proc;
+};
+
+/**************************************************************
+ ***  Function Declarations                          **********
+ **************************************************************/
+
+/**
+ * Creates a new entry at the tail of the DLL
+ * 
+ * @param h handle to the master context
+ * 
+ * @return pointer to the entry
+ */
+static struct GNUNET_VECTORPRODUCT_QueueEntry *
+make_queue_entry (struct GNUNET_VECTORPRODUCT_Handle *h);
+
+/**
+ * Removes the head entry from the queue
+ * 
+ * @param h Handle to the master context
+ */
+static struct GNUNET_VECTORPRODUCT_QueueEntry *
+free_queue_head_entry (struct GNUNET_VECTORPRODUCT_Handle * h);
+
+/**
+ * Triggered when timeout occurs for a request in queue
+ * 
+ * @param cls The pointer to the QueueEntry
+ * @param tc Task Context
+ */
+static void
+timeout_queue_entry (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+/**
+ * Called when a response is received from the service. After basic check
+ * handler in qe->response_proc is called. This functions handles the response
+ * to the client which used the API.
+ * 
+ * @param cls Pointer to the Master Context
+ * @param msg Pointer to the data received in response
+ */
+static void
+receive_cb (void *cls, const struct GNUNET_MessageHeader *msg);
+
+/**
+ * Transmits the request to the VectorProduct Sevice
+ * 
+ * @param cls Closure
+ * @param size Size of the buffer
+ * @param buf Pointer to the buffer
+ * 
+ * @return Size of the message sent
+ */
+static size_t transmit_request (void *cls, size_t size,
+                                void *buf);
+
+/**
+ * Issues transmit request for the new entries in the queue
+ * 
+ * @param h handle to the master context
+ */
+static void
+process_queue (struct GNUNET_VECTORPRODUCT_Handle *h);
+
+/**************************************************************
+ ***  Static Function Declarations                   **********
+ **************************************************************/
+
+
+/**
+ * Creates a new entry at the tail of the DLL
+ * 
+ * @param h handle to the master context
+ * 
+ * @return pointer to the entry
+ */
+static struct GNUNET_VECTORPRODUCT_QueueEntry *
+make_queue_entry (struct GNUNET_VECTORPRODUCT_Handle *h)
+{
+  struct GNUNET_VECTORPRODUCT_QueueEntry *qe;
+
+  qe = GNUNET_new (struct GNUNET_VECTORPRODUCT_QueueEntry);
+
+  // if queue empty
+  if (NULL == h->queue_head && NULL == h->queue_tail)
+    {
+      qe->next = NULL;
+      qe->prev = NULL;
+      h->queue_head = qe;
+      h->queue_tail = qe;
+    }
+  else
+    {
+      qe->prev = h->queue_tail;
+      h->queue_tail->next = qe;
+      h->queue_tail = qe;
+    }
+
+  return qe;
+}
+
+
+/**
+ * Removes the head entry from the queue
+ * 
+ * @param h Handle to the master context
+ */
+static struct GNUNET_VECTORPRODUCT_QueueEntry *
+free_queue_head_entry (struct GNUNET_VECTORPRODUCT_Handle * h)
+{
+  struct GNUNET_VECTORPRODUCT_QueueEntry * qe = NULL;
+
+  GNUNET_assert (NULL != h);
+  if (NULL == h->queue_head && NULL == h->queue_tail)
+    {
+      // The queue is empty. Just return.
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "Queue was empty when 
free_queue_head_entry was called.\n");
+    }
+  else if (h->queue_head == h->queue_tail) //only one entry
+    {
+      qe = h->queue_head;
+      qe->next = NULL;
+      qe->prev = NULL;
+      h->queue_head = NULL;
+      h->queue_tail = NULL;
+    }
+  else
+    {
+      qe = h->queue_head;
+      h->queue_head = h->queue_head->next;
+      h->queue_head->prev = NULL;
+      qe->next = NULL;
+      qe->prev = NULL;
+    }
+  return qe;
+}
+
+
+/**
+ * Triggered when timeout occurs for a request in queue
+ * 
+ * @param cls The pointer to the QueueEntry
+ * @param tc Task Context
+ */
+static void
+timeout_queue_entry (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct GNUNET_VECTORPRODUCT_QueueEntry * qe = cls;
+
+  // Update Statistics
+  GNUNET_STATISTICS_update (qe->h->stats,
+                            gettext_noop ("# queue entry timeouts"), 1,
+                            GNUNET_NO);
+
+  // Clear the timeout_task
+  qe->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+
+  // transmit_request is supposed to cancel timeout task.
+  // If message was not transmitted, there is definitely an error.
+  GNUNET_assert (GNUNET_NO == qe->was_transmitted);
+
+  LOG (GNUNET_ERROR_TYPE_INFO, "Timeout of request in datastore queue\n");
+
+  // remove the queue_entry for the queue
+  GNUNET_CONTAINER_DLL_remove (qe->h->queue_head, qe->h->queue_tail, qe);
+  qe->response_proc (qe, NULL, GNUNET_VECTORPRODUCT_Status_Timeout);
+}
+
+
+/**
+ * Handles the RESULT received in reply of prepare_response from the 
+ * service
+ * 
+ * @param cls Handle to the Master Context
+ * @param msg Pointer to the response received
+ */
+static void
+process_status_message (void *cls,
+                        const struct GNUNET_MessageHeader *msg,
+                        enum GNUNET_VECTORPRODUCT_ResponseStatus status)
+{
+  struct GNUNET_VECTORPRODUCT_QueueEntry *qe = cls;
+
+  GNUNET_assert (qe != NULL);
+
+  if (qe->cont_status != NULL)
+    qe->cont_status (qe->cont_cls, &qe->msg->key, status);
+}
+
+
+/**
+ * Handles the RESULT received in reply of prepare_response from the 
+ * service
+ * 
+ * @param cls Handle to the Master Context
+ * @param msg Pointer to the response received
+ */
+static void
+process_result_message (void *cls,
+                        const struct GNUNET_MessageHeader *msg,
+                        enum GNUNET_VECTORPRODUCT_ResponseStatus status)
+{
+  struct GNUNET_VECTORPRODUCT_QueueEntry *qe = cls;
+
+  GNUNET_assert (qe != NULL);
+
+  if (msg == NULL && qe->cont_datum != NULL)
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "Timeout reached or session 
terminated.\n");
+    }
+  if (qe->cont_datum != NULL)
+    {
+      qe->cont_datum (qe->cont_cls, &qe->msg->key, &qe->msg->peer, status, 
(struct GNUNET_VECTORPRODUCT_client_response *) msg);
+    }
+}
+
+
+/**
+ * Called when a response is received from the service. After basic check
+ * handler in qe->response_proc is called. This functions handles the response
+ * to the client which used the API.
+ * 
+ * @param cls Pointer to the Master Context
+ * @param msg Pointer to the data received in response
+ */
+static void
+receive_cb (void *cls, const struct GNUNET_MessageHeader *msg)
+{
+  struct GNUNET_VECTORPRODUCT_Handle *h = cls;
+  struct GNUNET_VECTORPRODUCT_QueueEntry *qe;
+  int16_t was_transmitted;
+  struct GNUNET_VECTORPRODUCT_client_response *message =
+          (struct GNUNET_VECTORPRODUCT_client_response *) msg;
+
+  h->in_receive = GNUNET_NO;
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Received reply from VectorProduct\n");
+
+  if (NULL == (qe = free_queue_head_entry (h)))
+    {
+      /**
+       * The queue head will be NULL if the client disconnected,
+       * * In case of Alice, client disconnected after sending request, before 
receiving response
+       * * In case of Bob, client disconnected after preparing response, 
before getting request from Alice.
+       */
+      process_queue (h);
+      return;
+    }
+
+  if (h->client == NULL)
+    {
+      // GKUKREJA : handle this correctly
+      /**
+       * The queue head will be NULL if the client disconnected,
+       * * In case of Alice, client disconnected after sending request, before 
receiving response
+       * * In case of Bob, client disconnected after preparing response, 
before getting request from Alice.
+       */
+      process_queue (h);
+      return;
+    }
+
+  was_transmitted = qe->was_transmitted;
+  // Control will only come here, when the request was transmitted to service,
+  // and service responded.
+  GNUNET_assert (was_transmitted == GNUNET_YES);
+
+  if (msg == NULL)
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Service responded with NULL!\n");
+      qe->response_proc (qe, NULL, GNUNET_VECTORPRODUCT_Status_Failure);
+    }
+  else if ((ntohs (msg->type) != 
GNUNET_MESSAGE_TYPE_VECTORPRODUCT_SERVICE_TO_CLIENT))
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid Message Received\n");
+      qe->response_proc (qe, msg, GNUNET_VECTORPRODUCT_Status_InvalidResponse);
+    }
+  else if (ntohl (message->product_length) == 0)
+    {
+      // response for the responder client, successful
+      GNUNET_STATISTICS_update (h->stats,
+                                gettext_noop ("# SUC responder result messages 
received"), 1,
+                                GNUNET_NO);
+
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "Received message from service without 
product attached.\n");
+      qe->response_proc (qe, msg, GNUNET_VECTORPRODUCT_Status_Success);
+    }
+  else if (ntohl (message->product_length) > 0)
+    {
+      // response for the requester client, successful
+      GNUNET_STATISTICS_update (h->stats,
+                                gettext_noop ("# SUC requester result messages 
received"), 1,
+                                GNUNET_NO);
+
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "Received message from requester service 
for requester client.\n");
+      qe->response_proc (qe, msg, GNUNET_VECTORPRODUCT_Status_Success);
+    }
+
+  GNUNET_free (qe);
+  process_queue (h);
+}
+
+
+/**
+ * Transmits the request to the VectorProduct Sevice
+ * 
+ * @param cls Closure
+ * @param size Size of the buffer
+ * @param buf Pointer to the buffer
+ * 
+ * @return Size of the message sent
+ */
+static size_t
+transmit_request (void *cls, size_t size,
+                  void *buf)
+{
+  struct GNUNET_VECTORPRODUCT_Handle *h = cls;
+  struct GNUNET_VECTORPRODUCT_QueueEntry *qe;
+  size_t msize;
+  
+  if (NULL == (qe = h->queue_head))
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "Queue head is NULL!\n\n");
+      return 0;
+    }
+
+  GNUNET_SCHEDULER_cancel (qe->timeout_task);
+  qe->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+
+  h->th = NULL;
+  if (NULL == (qe = h->queue_head))
+    return 0; /* no entry in queue */
+  if (buf == NULL)
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to transmit request to 
VECTORPRODUCT.\n");
+      GNUNET_STATISTICS_update (h->stats,
+                                gettext_noop ("# transmission request 
failures"),
+                                1, GNUNET_NO);
+      GNUNET_VECTORPRODUCT_disconnect (h);
+      return 0;
+    }
+  if (size < (msize = qe->message_size))
+    {
+      process_queue (h);
+      return 0;
+    }
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting %u byte request to 
VECTORPRODUCT\n",
+       msize);
+
+  memcpy (buf, qe->msg, size);
+  GNUNET_free (qe->msg);
+  qe->was_transmitted = GNUNET_YES;
+
+  GNUNET_assert (GNUNET_NO == h->in_receive);
+  h->in_receive = GNUNET_YES;
+
+  GNUNET_CLIENT_receive (h->client, &receive_cb, h,
+                         GNUNET_TIME_UNIT_FOREVER_REL);
+
+#if INSANE_STATISTICS
+  GNUNET_STATISTICS_update (h->stats,
+                            gettext_noop ("# bytes sent to vectorproduct"), 1,
+                            GNUNET_NO);
+#endif
+  return size;
+}
+
+
+/**
+ * Issues transmit request for the new entries in the queue
+ * 
+ * @param h handle to the master context
+ */
+static void
+process_queue (struct GNUNET_VECTORPRODUCT_Handle *h)
+{
+  struct GNUNET_VECTORPRODUCT_QueueEntry *qe;
+  
+  if (NULL == (qe = h->queue_head))
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "Queue empty\n");
+      return; /* no entry in queue */
+    }
+  if (qe->was_transmitted == GNUNET_YES)
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "Head request already transmitted\n");
+      return; /* waiting for replies */
+    }
+  if (h->th != NULL)
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "Pending transmission request\n");
+      return; /* request pending */
+    }
+  if (h->client == NULL)
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "Not connected\n");
+      return; /* waiting for reconnect */
+    }
+  if (GNUNET_YES == h->in_receive)
+    {
+      /* wait for response to previous query */
+      return;
+    }
+
+  h->th =
+          GNUNET_CLIENT_notify_transmit_ready (h->client, qe->message_size,
+                                               GNUNET_TIME_UNIT_FOREVER_REL,
+                                               GNUNET_YES,
+                                               &transmit_request, h);
+
+  if (h->th == NULL)
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR,
+           _ ("Failed to send a message to the vectorproduct service\n"));
+      return;
+    }
+
+  GNUNET_assert (GNUNET_NO == h->in_receive);
+  GNUNET_break (NULL != h->th);
+}
+
+
+
+/**************************************************************
+ ***  API                                            **********
+ **************************************************************/
+
+
+/**
+ * Called by the responder client to prepare response
+ * 
+ * @param h handle to the master context
+ * @param key Session key - unique to the requesting client
+ * @param element_count Number of elements in the vector
+ * @param mask_length number of bytes in the mask
+ * @param elements Array of elements of the vector
+ * @param mask Array of the mask
+ * @param timeout Relative timeout for the operation
+ * @param cont Callback function
+ * @param cont_cls Closure for the callback function
+ */
+struct GNUNET_VECTORPRODUCT_QueueEntry *
+GNUNET_VECTORPRODUCT_prepare_response (struct GNUNET_VECTORPRODUCT_Handle *h,
+                                       const struct GNUNET_HashCode * key,
+                                       uint16_t element_count,
+                                       int32_t * elements,
+                                       struct GNUNET_TIME_Relative timeout,
+                                       
GNUNET_VECTORPRODUCT_ContinuationWithStatus cont,
+                                       void *cont_cls)
+{
+  struct GNUNET_VECTORPRODUCT_QueueEntry *qe = make_queue_entry (h);
+  int32_t * vector;
+  uint16_t size;
+  unsigned int i;
+  
+  GNUNET_assert (GNUNET_SERVER_MAX_MESSAGE_SIZE >= sizeof (struct 
GNUNET_VECTORPRODUCT_client_request)
+                 +element_count * sizeof (int32_t));
+  size = sizeof (struct GNUNET_VECTORPRODUCT_client_request) +element_count * 
sizeof (int32_t);
+
+  qe->message_size = size;
+  qe->msg = GNUNET_malloc (size);
+  qe->msg->header.size = htons (size);
+  qe->msg->header.type = htons 
(GNUNET_MESSAGE_TYPE_VECTORPRODUCT_CLIENT_TO_BOB);
+  qe->msg->element_count = htons (element_count);
+  qe->msg->mask_length = htons (0);
+  memcpy (&qe->msg->key, key, sizeof (struct GNUNET_HashCode));
+  qe->cont_status = cont;
+  qe->cont_cls = cont_cls;
+  qe->was_transmitted = GNUNET_NO;
+  qe->timeout_task = GNUNET_SCHEDULER_add_delayed (timeout, 
&timeout_queue_entry, qe);
+  qe->response_proc = &process_status_message;
+  qe->timeout = GNUNET_TIME_relative_to_absolute (timeout);
+
+  vector = (int32_t *) & qe->msg[1];
+  // copy each element over to the message
+  for (i = 0; i < element_count; i++)
+    vector[i] = htonl (elements[i]);
+
+  process_queue (h);
+  return qe;
+}
+
+
+/**
+ * Request the Scalar Product Evaluation
+ * 
+ * @param h handle to the master context
+ * @param key Session key - unique to the requesting client
+ * @param peer PeerID of the other peer
+ * @param element_count Number of elements in the vector
+ * @param mask_length number of bytes in the mask
+ * @param elements Array of elements of the vector
+ * @param mask Array of the mask
+ * @param timeout Relative timeout for the operation
+ * @param cont Callback function
+ * @param cont_cls Closure for the callback function
+ */
+struct GNUNET_VECTORPRODUCT_QueueEntry *
+GNUNET_VECTORPRODUCT_request (struct GNUNET_VECTORPRODUCT_Handle *h,
+                              const struct GNUNET_HashCode * key,
+                              const struct GNUNET_PeerIdentity * peer,
+                              uint16_t element_count,
+                              uint16_t mask_length,
+                              int32_t * elements,
+                              const unsigned char * mask,
+                              struct GNUNET_TIME_Relative timeout,
+                              GNUNET_VECTORPRODUCT_DatumProcessor cont,
+                              void *cont_cls)
+{
+  struct GNUNET_VECTORPRODUCT_QueueEntry *qe = make_queue_entry (h);
+  int32_t * vector;
+  uint16_t size;
+  unsigned int i;
+  
+  GNUNET_assert (GNUNET_SERVER_MAX_MESSAGE_SIZE >= sizeof (struct 
GNUNET_VECTORPRODUCT_client_request)
+                 +element_count * sizeof (int32_t)
+                 + mask_length);
+  size = sizeof (struct GNUNET_VECTORPRODUCT_client_request) +element_count * 
sizeof (int32_t) + mask_length;
+
+  qe->message_size = size;
+  qe->msg = GNUNET_malloc (size);
+  qe->msg->header.size = htons (size);
+  qe->msg->header.type = htons 
(GNUNET_MESSAGE_TYPE_VECTORPRODUCT_CLIENT_TO_ALICE);
+  memcpy (&qe->msg->peer, peer, sizeof (struct GNUNET_PeerIdentity));
+  qe->msg->element_count = htons (element_count);
+  qe->msg->mask_length = htons (mask_length);
+  memcpy (&qe->msg->key, key, sizeof (struct GNUNET_HashCode));
+  qe->cont_datum = cont;
+  qe->cont_cls = cont_cls;
+  qe->was_transmitted = GNUNET_NO;
+  qe->timeout_task = GNUNET_SCHEDULER_add_delayed (timeout, 
&timeout_queue_entry, qe);
+  qe->response_proc = &process_result_message;
+  qe->timeout = GNUNET_TIME_relative_to_absolute (timeout);
+
+  vector = (int32_t*) & qe->msg[1];
+  // copy each element over to the message
+  for (i = 0; i < element_count; i++)
+    vector[i] = htonl (elements[i]);
+
+  // fill in the mask
+  memcpy (&vector[element_count], mask, mask_length);
+
+  process_queue (h);
+  return qe;
+}
+
+
+/**
+ * Connect to the vectorproduct service.
+ *
+ * @param cfg configuration to use
+ * @return handle to use to access the service
+ */
+struct GNUNET_VECTORPRODUCT_Handle *
+GNUNET_VECTORPRODUCT_connect (const struct GNUNET_CONFIGURATION_Handle * cfg)
+{
+  struct GNUNET_CLIENT_Connection *client;
+  struct GNUNET_VECTORPRODUCT_Handle *h;
+
+  client = GNUNET_CLIENT_connect ("vectorproduct", cfg);
+
+  if (NULL == client)
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR,
+           _ ("Failed to connect to the vectorproduct service\n"));
+      return NULL;
+    }
+
+  h = GNUNET_malloc (sizeof (struct GNUNET_VECTORPRODUCT_Handle) +
+                     GNUNET_SERVER_MAX_MESSAGE_SIZE - 1);
+  h->client = client;
+  h->cfg = cfg;
+  h->stats = GNUNET_STATISTICS_create ("vectorproduct-api", cfg);
+  return h;
+}
+
+
+/**
+ * Disconnect from the vectorproduct service.
+ * 
+ * @param h handle to the vectorproduct
+ */
+void
+GNUNET_VECTORPRODUCT_disconnect (struct GNUNET_VECTORPRODUCT_Handle * h)
+{
+  struct GNUNET_VECTORPRODUCT_QueueEntry * qe;
+
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "Disconnecting from VectorProduct\n");
+
+  while (NULL != h->queue_head)
+    {
+      GNUNET_assert (NULL != (qe = free_queue_head_entry (h)));
+      qe->response_proc (qe, NULL, 
GNUNET_VECTORPRODUCT_Status_ServiceDisconnected);
+    }
+
+  if (h->client != NULL)
+    {
+      GNUNET_CLIENT_disconnect (h->client);
+      h->client = NULL;
+    }
+
+  GNUNET_STATISTICS_destroy (h->stats, GNUNET_NO);
+  h->stats = NULL;
+}
+
+/* end of ext_api.c */

Added: gnunet/src/vectorproduct/vectorproduct_testing.h
===================================================================
--- gnunet/src/vectorproduct/vectorproduct_testing.h                            
(rev 0)
+++ gnunet/src/vectorproduct/vectorproduct_testing.h    2013-08-22 13:41:49 UTC 
(rev 28794)
@@ -0,0 +1,129 @@
+/* 
+ * File:   vectorproduct_testing.h
+ * Author: gnunet
+ *
+ * Created on June 29, 2013, 7:39 PM
+ */
+
+#ifndef VECTORPRODUCT_TESTING_H
+#define        VECTORPRODUCT_TESTING_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+    
+struct GNUNET_VECTORPRODUCT_TESTING_handle
+{
+  /**
+   * Testing library system handle
+   */
+  struct GNUNET_TESTING_System *tl_system;
+  
+  /**
+   * head DLL of peers
+   */
+  struct PeerContext *p_head;
+
+  /**
+   * tail DLL of peers
+   */
+  struct PeerContext *p_tail;
+};
+
+struct PeerContext 
+{
+  /**
+   * Next element in the DLL
+   */
+  struct PeerContext *next;
+
+  /**
+   * Previous element in the DLL
+   */
+  struct PeerContext *prev;
+
+  /**
+   * Peer's testing handle
+   */
+  struct GNUNET_TESTING_Peer *peer;
+
+  /**
+   * Peer identity
+   */
+  struct GNUNET_PeerIdentity id;
+  
+  /**
+   * Handle for the peer's ARM process
+   */
+  struct GNUNET_OS_Process *arm_proc;
+  
+  /**
+   * Pointer to Vector Product Handle
+   */
+  struct GNUNET_VECTORPRODUCT_Handle *vh;
+  
+  /**
+   * Closure for the callbacks
+   */
+  void *cb_cls;
+
+  /**
+   * An unique number to identify the peer
+   */
+  unsigned int no;
+  
+  /**
+   * Peer's configuration
+   */
+  struct GNUNET_CONFIGURATION_Handle *cfg;
+  
+  /**
+   * Pointer to the master testing handle
+   */
+  struct GNUNET_VECTORPRODUCT_TESTING_handle * vth;
+  
+  /**
+    * Callback when two peers are connected and both have called the connect 
callback
+    * to notify clients about a new peer
+    */
+   void (*start_cb) (struct PeerContext * p, void *cls);
+  
+//  /**
+//   * Pointer to function where the test occurs
+//   */
+//  GNUNET_VECTORPRODUCT_TESTING_start_cb start_cb;
+};
+
+/**
+ * Callback when two peers are connected and both have called the connect 
callback
+ * to notify clients about a new peer
+ */
+typedef void (*GNUNET_VECTORPRODUCT_TESTING_start_cb) (struct PeerContext * p,
+                                                   void *cls);
+
+struct GNUNET_VECTORPRODUCT_TESTING_handle *
+GNUNET_VECTORPRODUCT_TESTING_init();
+
+static void
+GNUNET_VECTORPRODUCT_TESTING_done(struct GNUNET_VECTORPRODUCT_TESTING_handle * 
vth);
+
+struct PeerContext *
+GNUNET_VECTORPRODUCT_TESTING_start_peer (struct 
GNUNET_VECTORPRODUCT_TESTING_handle * vth,
+                                     const char *cfgname, int peer_id,
+                                     GNUNET_VECTORPRODUCT_TESTING_start_cb 
start_cb,
+                                     void *cb_cls);
+
+static void
+GNUNET_VECTORPRODUCT_TESTING_stop_peer
+        (struct GNUNET_VECTORPRODUCT_TESTING_handle * vth,
+        struct PeerContext *p);
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* VECTORPRODUCT_TESTING_H */
+




reply via email to

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