aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Fuchs <christian.fuchs@cfuchs.net>2013-08-22 13:41:49 +0000
committerChristian Fuchs <christian.fuchs@cfuchs.net>2013-08-22 13:41:49 +0000
commit3003feb0b391420b403654d840d3c67404fab048 (patch)
tree4da537dcded885418f9b7d357a7a8c73176ab4b2
parentf14d78e3c6555f5721705c587e01e8e10503de19 (diff)
downloadgnunet-3003feb0b391420b403654d840d3c67404fab048.tar.gz
gnunet-3003feb0b391420b403654d840d3c67404fab048.zip
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
-rw-r--r--doc/man/Makefile.am1
-rw-r--r--doc/man/gnunet-vectorproduct.165
-rw-r--r--po/POTFILES.in3
-rw-r--r--src/Makefile.am2
-rw-r--r--src/include/gnunet_applications.h5
-rw-r--r--src/include/gnunet_protocols.h33
-rw-r--r--src/include/gnunet_vectorproduct_service.h265
-rw-r--r--src/vectorproduct/Makefile.am97
-rw-r--r--src/vectorproduct/gnunet-service-vectorproduct.c2067
-rw-r--r--src/vectorproduct/gnunet-vectorproduct.c410
-rw-r--r--src/vectorproduct/gnunet_vectorproduct.h274
-rw-r--r--src/vectorproduct/test_vectorproduct_api.c865
-rw-r--r--src/vectorproduct/test_vectorproduct_api_4peers.c1084
-rw-r--r--src/vectorproduct/test_vectorproduct_api_data.conf96
-rw-r--r--src/vectorproduct/test_vectorproduct_api_regression.c852
-rw-r--r--src/vectorproduct/test_vectorproduct_api_regression2.c931
-rw-r--r--src/vectorproduct/vectorproduct.conf.in7
-rw-r--r--src/vectorproduct/vectorproduct_api.c715
-rw-r--r--src/vectorproduct/vectorproduct_testing.h129
19 files changed, 7899 insertions, 2 deletions
diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am
index 9e63bb243..8657c2365 100644
--- a/doc/man/Makefile.am
+++ b/doc/man/Makefile.am
@@ -27,6 +27,7 @@ man_MANS = \
27 gnunet-transport.1 \ 27 gnunet-transport.1 \
28 gnunet-unindex.1 \ 28 gnunet-unindex.1 \
29 gnunet-uri.1 \ 29 gnunet-uri.1 \
30 gnunet-vectorproduct.1 \
30 gnunet-vpn.1 31 gnunet-vpn.1
31 32
32EXTRA_DIST = ${man_MANS} 33EXTRA_DIST = ${man_MANS}
diff --git a/doc/man/gnunet-vectorproduct.1 b/doc/man/gnunet-vectorproduct.1
new file mode 100644
index 000000000..6852694b6
--- /dev/null
+++ b/doc/man/gnunet-vectorproduct.1
@@ -0,0 +1,65 @@
1.TH GNUNET\-VECTORPRODUCT 1 "8 Aug 2013" "GNUnet"
2
3.SH NAME
4gnunet\-vectorproduct \- compute a vectorproduct
5
6.SH SYNOPSIS
7.B gnunet\-vectorproduct
8.RI [ options ]
9.br
10
11.SH DESCRIPTION
12\fBgnunet-vectorproduct\fP enables you to compute a vectorproduct across two peers \fBAlice\fP and \fBBob\fP.
13
14A client can issue one of two messages to its service:
15.TS
16tab (@);
17l lx.
181@T{
19A request to compute a vectorproduct with another peer (\fBAlice\fP)
20T}
212@T{
22Elements to support a peer in computing a vectorproduct (\fBBob\fP)
23T}
24.TE
25
26Both 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.
27
28\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.
29
30Elements 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.
31
32The 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.
33
34.SH OPTIONS
35.B
36.IP "\-e ELEMENTS, \-\-elements=ELEMENTS"
37The 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.
38.B
39.IP "\-m MASK, \-\-mask=MASK"
40Elements 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.
41.B
42.IP "\-k KEY, \-\-key=KEY"
43The session key, a shared string of arbitrary length from which the SID will be generated
44.B
45.IP "\-c FILENAME, \-\-config=FILENAME"
46Use the configuration file FILENAME.
47.B
48.IP "\-p PEERID, \-\-peer=PEERID"
49The 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.
50.B
51.IP "\-h, \-\-help"
52Print short help on options.
53.B
54.IP "\-L LOGLEVEL, \-\-loglevel=LOGLEVEL"
55Use LOGLEVEL for logging. Valid values are DEBUG, INFO, WARNING and ERROR.
56.B
57.IP "\-v, \-\-version"
58Print GNUnet version number.
59
60
61.SH BUGS
62Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending electronic mail to <gnunet\-developers@gnu.org>
63
64.SH SEE ALSO
65gnunet\-peerinfo(1)
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 18fd7ab06..cd4e05fae 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -343,3 +343,6 @@ src/mesh/mesh_protocol.h
343src/mesh/mesh_protocol_enc.h 343src/mesh/mesh_protocol_enc.h
344src/testbed/testbed_api.h 344src/testbed/testbed_api.h
345src/testbed/testbed_api_operations.h 345src/testbed/testbed_api_operations.h
346src/vectorproduct/vectorproduct_api.c
347src/vectorproduct/gnunet-service-vectorproduct.c
348src/vectorproduct/gnunet-vectorproduct.c
diff --git a/src/Makefile.am b/src/Makefile.am
index b77025a3e..524098992 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -7,10 +7,12 @@ if HAVE_TESTING
7 TESTBED = testbed 7 TESTBED = testbed
8 CONSENSUS = consensus 8 CONSENSUS = consensus
9 EXPERIMENTATION = experimentation 9 EXPERIMENTATION = experimentation
10 VECTORPRODUCT = vectorproduct
10endif 11endif
11 12
12if HAVE_EXPERIMENTAL 13if HAVE_EXPERIMENTAL
13 EXP_DIR = dv $(CONSENSUS) $(EXPERIMENTATION) 14 EXP_DIR = dv $(CONSENSUS) $(EXPERIMENTATION)
15#note: vectorproduct is not being listed here yet as the crypto is being reworked at the moment
14endif 16endif
15 17
16if HAVE_MYSQL 18if HAVE_MYSQL
diff --git a/src/include/gnunet_applications.h b/src/include/gnunet_applications.h
index 4e86e332e..866ea0140 100644
--- a/src/include/gnunet_applications.h
+++ b/src/include/gnunet_applications.h
@@ -76,12 +76,15 @@ extern "C"
76 */ 76 */
77#define GNUNET_APPLICATION_TYPE_CONSENSUS 18 77#define GNUNET_APPLICATION_TYPE_CONSENSUS 18
78 78
79
80/** 79/**
81 * Set. Used for two-peer set operations implemented using stream. 80 * Set. Used for two-peer set operations implemented using stream.
82 */ 81 */
83#define GNUNET_APPLICATION_TYPE_SET 19 82#define GNUNET_APPLICATION_TYPE_SET 19
84 83
84/**
85 * Vectorproduct. Used for two-peer vectorproduct operations
86 */
87#define GNUNET_APPLICATION_TYPE_VECTORPRODUCT 20
85 88
86#if 0 /* keep Emacsens' auto-indent happy */ 89#if 0 /* keep Emacsens' auto-indent happy */
87{ 90{
diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h
index a62b286af..dfd7c5506 100644
--- a/src/include/gnunet_protocols.h
+++ b/src/include/gnunet_protocols.h
@@ -1905,8 +1905,39 @@ extern "C"
1905#define GNUNET_MESSAGE_TYPE_IDENTITY_DELETE 631 1905#define GNUNET_MESSAGE_TYPE_IDENTITY_DELETE 631
1906 1906
1907 1907
1908/*******************************************************************************
1909 * VECTORPRODUCT message types
1910 ******************************************************************************/
1911
1912/**
1913 * Client -> Vector-Product Service request message
1914 */
1915#define GNUNET_MESSAGE_TYPE_VECTORPRODUCT_CLIENT_TO_ALICE 640
1916
1917/**
1918 * Client -> Vector-Product Service request message
1919 */
1920#define GNUNET_MESSAGE_TYPE_VECTORPRODUCT_CLIENT_TO_BOB 641
1921
1922/**
1923 * Vector-Product Service request -> remote VP Service
1924 */
1925#define GNUNET_MESSAGE_TYPE_VECTORPRODUCT_ALICE_TO_BOB 642
1926
1927/**
1928 * remote Vector-Product Service response -> requesting VP Service
1929 */
1930#define GNUNET_MESSAGE_TYPE_VECTORPRODUCT_BOB_TO_ALICE 643
1931
1932/**
1933 * Vector-Product Service response -> Client
1934 */
1935#define GNUNET_MESSAGE_TYPE_VECTORPRODUCT_SERVICE_TO_CLIENT 644
1936
1937
1938
1908/** 1939/**
1909 * Next available: 640 1940 * Next available: 650
1910 */ 1941 */
1911 1942
1912 1943
diff --git a/src/include/gnunet_vectorproduct_service.h b/src/include/gnunet_vectorproduct_service.h
new file mode 100644
index 000000000..743a7365d
--- /dev/null
+++ b/src/include/gnunet_vectorproduct_service.h
@@ -0,0 +1,265 @@
1/*
2 This file is part of GNUnet.
3 (C) 2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
21/**
22 * @file include/gnunet_vectorproduct_service.h
23 * @brief API to the vectorproduct service
24 * @author Christian M. Fuchs
25 * @author Gaurav Kukreja
26 */
27#ifndef GNUNET_VECTORPRODUCT_SERVICE_H
28#define GNUNET_VECTORPRODUCT_SERVICE_H
29#define GCRYPT_NO_DEPRECATED
30// including gcrypt crashes netbeans after the next restart...
31#include <gcrypt.h>
32
33#ifdef __cplusplus
34extern "C" {
35#if 0 /* keep Emacsens' auto-indent happy */
36}
37#endif
38#endif
39
40/**
41 * Version of the vectorproduct API.
42 */
43#define GNUNET_VECTORPRODUCT_VERSION 0x00000042
44
45/**
46 * Message type passed from client to service
47 * to initiate a request or responder role
48 */
49struct GNUNET_VECTORPRODUCT_client_request {
50 /**
51 * GNUNET message header
52 */
53 struct GNUNET_MessageHeader header;
54
55 /**
56 * how many elements the vector in payload contains
57 */
58 uint16_t element_count GNUNET_PACKED;
59
60 /**
61 * how many bytes the mask has
62 */
63 uint16_t mask_length GNUNET_PACKED;
64
65 /**
66 * the transaction/session key used to identify a session
67 */
68 struct GNUNET_HashCode key;
69
70 /**
71 * the identity of a remote peer we want to communicate with
72 */
73 struct GNUNET_PeerIdentity peer;
74
75 /**
76 * followed by long vector[element_count] | [unsigned char mask[mask_bytes]]
77 */
78};
79
80/**
81 * Message type passed from service client
82 * to finalize a session as requester or responder
83 */
84struct GNUNET_VECTORPRODUCT_client_response {
85 /**
86 * GNUNET message header
87 */
88 struct GNUNET_MessageHeader header;
89
90 /**
91 * 0 if no product attached
92 */
93 uint32_t product_length GNUNET_PACKED;
94
95 /**
96 * the transaction/session key used to identify a session
97 */
98 struct GNUNET_HashCode key;
99
100 /**
101 * the identity of a remote peer we want to communicate with
102 */
103 struct GNUNET_PeerIdentity peer;
104
105 /**
106 * followed by product of length product_length (or nothing)
107 */
108};
109
110enum GNUNET_VECTORPRODUCT_ResponseStatus {
111 GNUNET_VECTORPRODUCT_Status_Success = 0,
112 GNUNET_VECTORPRODUCT_Status_Failure,
113 GNUNET_VECTORPRODUCT_Status_Timeout,
114 GNUNET_VECTORPRODUCT_Status_InvalidResponse,
115 GNUNET_VECTORPRODUCT_Status_ServiceDisconnected
116};
117
118struct GNUNET_VECTORPRODUCT_Handle {
119 /**
120 * Our configuration.
121 */
122 const struct GNUNET_CONFIGURATION_Handle *cfg;
123
124 /**
125 * Current connection to the vectorproduct service.
126 */
127 struct GNUNET_CLIENT_Connection *client;
128
129 /**
130 * Handle for statistics.
131 */
132 struct GNUNET_STATISTICS_Handle *stats;
133
134 /**
135 * Current head of priority queue.
136 */
137 struct GNUNET_VECTORPRODUCT_QueueEntry *queue_head;
138
139 /**
140 * Current tail of priority queue.
141 */
142 struct GNUNET_VECTORPRODUCT_QueueEntry *queue_tail;
143
144 /**
145 * Are we currently trying to receive from the service?
146 */
147 int in_receive;
148
149 /**
150 * Current transmit handle.
151 */
152 struct GNUNET_CLIENT_TransmitHandle *th;
153
154 /**
155 * TODO: What else should/could go here?
156 */
157};
158
159typedef void (*GNUNET_VECTORPRODUCT_ResponseMessageHandler) (void *cls,
160 const struct GNUNET_MessageHeader *msg,
161 enum GNUNET_VECTORPRODUCT_ResponseStatus status);
162
163/**
164 * Continuation called to notify client about result of the
165 * operation.
166 *
167 * @param cls closure
168 * @param success GNUNET_SYSERR on failure (including timeout/queue drop)
169 * GNUNET_NO if content was already there
170 * GNUNET_YES (or other positive value) on success
171 * @param msg NULL on success, otherwise an error message
172 */
173typedef void (*GNUNET_VECTORPRODUCT_ContinuationWithStatus) (void *cls,
174 const struct GNUNET_HashCode * key,
175 enum GNUNET_VECTORPRODUCT_ResponseStatus status);
176/**
177 * Process a datum that was stored in the vectorproduct.
178 *
179 * @param cls closure
180 * @param key Sessioon key
181 * @param peer PeerID of the peer with whom the scalar product was calculated.
182 * @param status Status of the request
183 * @param size Size of the received message
184 * @param data Pointer to the data
185 * @param type Type of data
186 */
187typedef void (*GNUNET_VECTORPRODUCT_DatumProcessor) (void *cls,
188 const struct GNUNET_HashCode * key,
189 const struct GNUNET_PeerIdentity * peer,
190 enum GNUNET_VECTORPRODUCT_ResponseStatus status,
191 const struct GNUNET_VECTORPRODUCT_client_response *msg);
192
193/**
194 * Request the Scalar Product Evaluation
195 *
196 * @param h handle to the master context
197 * @param key Session key - unique to the requesting client
198 * @param peer PeerID of the other peer
199 * @param element_count Number of elements in the vector
200 * @param mask_bytes number of bytes in the mask
201 * @param elements Array of elements of the vector
202 * @param mask Array of the mask
203 * @param timeout Relative timeout for the operation
204 * @param cont Callback function
205 * @param cont_cls Closure for the callback function
206 */
207struct GNUNET_VECTORPRODUCT_QueueEntry *
208GNUNET_VECTORPRODUCT_request(struct GNUNET_VECTORPRODUCT_Handle *h,
209 const struct GNUNET_HashCode * key,
210 const struct GNUNET_PeerIdentity *peer,
211 uint16_t element_count,
212 uint16_t mask_bytes,
213 int32_t * elements, const unsigned char * mask,
214 struct GNUNET_TIME_Relative timeout,
215 GNUNET_VECTORPRODUCT_DatumProcessor cont,
216 void *cont_cls);
217
218/**
219 * Called by the responder client to prepare response
220 *
221 * @param h handle to the master context
222 * @param key Session key - unique to the requesting client
223 * @param element_count Number of elements in the vector
224 * @param mask_bytes number of bytes in the mask
225 * @param elements Array of elements of the vector
226 * @param mask Array of the mask
227 * @param timeout Relative timeout for the operation
228 * @param cont Callback function
229 * @param cont_cls Closure for the callback function
230 */
231struct GNUNET_VECTORPRODUCT_QueueEntry *
232GNUNET_VECTORPRODUCT_prepare_response(struct GNUNET_VECTORPRODUCT_Handle *h,
233 const struct GNUNET_HashCode * key,
234 uint16_t element_count,
235 int32_t* elements,
236 struct GNUNET_TIME_Relative timeout,
237 GNUNET_VECTORPRODUCT_ContinuationWithStatus cont,
238 void *cont_cls);
239
240/**
241 * Connect to the vectorproduct service.
242 *
243 * @param cfg configuration to use
244 * @return handle to use to access the service
245 */
246struct GNUNET_VECTORPRODUCT_Handle *
247GNUNET_VECTORPRODUCT_connect(const struct GNUNET_CONFIGURATION_Handle * cfg);
248
249/**
250 * Disconnect from the vectorproduct service.
251 *
252 * @param h handle to the vectorproduct
253 */
254void
255GNUNET_VECTORPRODUCT_disconnect(struct GNUNET_VECTORPRODUCT_Handle * h);
256
257
258#if 0 /* keep Emacsens' auto-indent happy */
259{
260#endif
261#ifdef __cplusplus
262}
263#endif
264
265#endif
diff --git a/src/vectorproduct/Makefile.am b/src/vectorproduct/Makefile.am
new file mode 100644
index 000000000..e9cbbc644
--- /dev/null
+++ b/src/vectorproduct/Makefile.am
@@ -0,0 +1,97 @@
1SUBDIRS = .
2
3INCLUDES = \
4 -I$(top_srcdir)/src/include \
5 -I$(top_srcdir)
6
7AM_CPPFLAGS = \
8 $(GNUNET_CPPFLAGS)
9
10# Set this variable if you are using GNUNET libraries for all programs and
11# libraries. You don't then need to target-specific _LDFLAGS with GNUNET_LDFLAGS
12# AM_LDFLAGS = \
13# $(GNUNET_LDFLAGS) \
14# $(WINFLAGS) \
15# -export-dynamic
16
17lib_LTLIBRARIES = libgnunetvectorproduct.la
18
19pkgcfgdir= $(prefix)/share/gnunet/config.d/
20
21libexecdir= $(prefix)/lib/gnunet/libexec/
22
23libgnunetvectorproduct_la_SOURCES = \
24 vectorproduct_api.c
25libgnunetvectorproduct_la_LIBADD = \
26 -lgnunetutil -lgcrypt -lgnunetstatistics
27libgnunetvectorproduct_la_LDFLAGS = \
28 $(GNUNET_LDFLAGS) $(WINFLAGS) \
29 -version-info 0:0:0
30
31
32bin_PROGRAMS = gnunet-vectorproduct
33
34libexec_PROGRAMS = gnunet-service-vectorproduct
35
36check_PROGRAMS = \
37 test_vectorproduct_api_regression \
38 test_vectorproduct_api \
39 test_vectorproduct_api_4peers
40#FIXME unfinished
41#test_vectorproduct_api_regression2
42
43TESTS = $(check_PROGRAMS)
44
45gnunet_service_vectorproduct_SOURCES = \
46 gnunet-service-vectorproduct.c
47gnunet_service_vectorproduct_LDADD = \
48 -lgnunetutil -lgnunettransport -lgnunetcore -lgnunetmesh -lgnunetdht -lgcrypt \
49 $(INTLLIBS)
50gnunet_service_vectorproduct_LDFLAGS = \
51 $(GNUNET_LDFLAGS) $(WINFLAGS) -export-dynamic
52
53gnunet_vectorproduct_SOURCES = \
54 gnunet-vectorproduct.c
55gnunet_vectorproduct_LDADD = \
56 $(top_builddir)/src/vectorproduct/libgnunetvectorproduct.la \
57 -lgnunetutil -lgcrypt \
58 $(INTLLIBS)
59gnunet_vectorproduct_LDFLAGS = \
60 $(GNUNET_LDFLAGS) $(WINFLAGS) -export-dynamic
61
62
63test_vectorproduct_api_SOURCES = \
64 test_vectorproduct_api.c
65test_vectorproduct_api_LDADD = \
66 $(top_builddir)/src/vectorproduct/libgnunetvectorproduct.la \
67 -lgnunetutil -lgcrypt -lgnunetstatistics -lgnunettestbed
68test_vectorproduct_api_LDFLAGS = \
69 $(GNUNET_LDFLAGS) $(WINFLAGS) -export-dynamic
70
71#FIXME unfinished
72#test_vectorproduct_api_regression2_SOURCES = \
73# test_vectorproduct_api_regression2.c
74#test_vectorproduct_api_regression2_LDADD = \
75# $(top_builddir)/src/vectorproduct/libgnunetvectorproduct.la \
76# -lgnunetutil -lgcrypt -lgnunetstatistics -lgnunettestbed
77#test_vectorproduct_api_regression2_LDFLAGS = \
78# $(GNUNET_LDFLAGS) $(WINFLAGS) -export-dynamic
79
80test_vectorproduct_api_regression_SOURCES = \
81 test_vectorproduct_api_regression.c
82test_vectorproduct_api_regression_LDADD = \
83 $(top_builddir)/src/vectorproduct/libgnunetvectorproduct.la \
84 -lgnunetutil -lgcrypt -lgnunetstatistics -lgnunettestbed
85test_vectorproduct_api_regression_LDFLAGS = \
86 $(GNUNET_LDFLAGS) $(WINFLAGS) -export-dynamic
87
88test_vectorproduct_api_4peers_SOURCES = \
89 test_vectorproduct_api_4peers.c
90test_vectorproduct_api_4peers_LDADD = \
91 $(top_builddir)/src/vectorproduct/libgnunetvectorproduct.la \
92 -lgnunetutil -lgcrypt -lgnunetstatistics -lgnunettestbed
93test_vectorproduct_api_4peers_LDFLAGS = \
94 $(GNUNET_LDFLAGS) $(WINFLAGS) -export-dynamic
95
96 pkgcfg_DATA = vectorproduct.conf
97
diff --git a/src/vectorproduct/gnunet-service-vectorproduct.c b/src/vectorproduct/gnunet-service-vectorproduct.c
new file mode 100644
index 000000000..1c459a335
--- /dev/null
+++ b/src/vectorproduct/gnunet-service-vectorproduct.c
@@ -0,0 +1,2067 @@
1/*
2 This file is part of GNUnet.
3 (C) 2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
21/**
22 * @file vectorproduct/gnunet-service-vectorproduct.c
23 * @brief vectorproduct service implementation
24 * @author Christian M. Fuchs
25 */
26#include <limits.h>
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_core_service.h"
30#include "gnunet_mesh_service.h"
31#include "gnunet_applications.h"
32#include "gnunet_protocols.h"
33#include "gnunet_vectorproduct_service.h"
34#include "gnunet_vectorproduct.h"
35
36///////////////////////////////////////////////////////////////////////////////
37// Global Variables
38///////////////////////////////////////////////////////////////////////////////
39
40/**
41 * Handle to the core service (NULL until we've connected to it).
42 */
43static struct GNUNET_CORE_Handle *my_core;
44
45/**
46 * Handle to the core service (NULL until we've connected to it).
47 */
48static struct GNUNET_MESH_Handle *my_mesh;
49
50/**
51 * The identity of this host.
52 */
53static struct GNUNET_PeerIdentity me;
54
55/**
56 * Service's own public key represented as string
57 */
58static unsigned char * my_pubkey_external;
59
60/**
61 * Service's own public key represented as string
62 */
63static uint16_t my_pubkey_external_length = 0;
64
65/**
66 * Service's own n
67 */
68static gcry_mpi_t my_n;
69
70/**
71 * Service's own n^2 (kept for performance)
72 */
73static gcry_mpi_t my_nsquare;
74
75/**
76 * Service's own public exponent
77 */
78static gcry_mpi_t my_g;
79
80/**
81 * Service's own private multiplier
82 */
83static gcry_mpi_t my_mu;
84
85/**
86 * Service's own private exponent
87 */
88static gcry_mpi_t my_lambda;
89
90/**
91 * Head of our double linked list for client-requests sent to us.
92 * for all of these elements we calculate a vector product with a remote peer
93 * split between service->service and client->service for simplicity
94 */
95static struct ServiceSession * from_client_head;
96/**
97 * Tail of our double linked list for client-requests sent to us.
98 * for all of these elements we calculate a vector product with a remote peer
99 * split between service->service and client->service for simplicity
100 */
101static struct ServiceSession * from_client_tail;
102
103/**
104 * Head of our double linked list for service-requests sent to us.
105 * for all of these elements we help the requesting service in calculating a vector product
106 * split between service->service and client->service for simplicity
107 */
108static struct ServiceSession * from_service_head;
109
110/**
111 * Tail of our double linked list for service-requests sent to us.
112 * for all of these elements we help the requesting service in calculating a vector product
113 * split between service->service and client->service for simplicity
114 */
115static struct ServiceSession * from_service_tail;
116
117/**
118 * Certain events (callbacks for server & mesh operations) must not be queued after shutdown.
119 */
120static int do_shutdown;
121
122///////////////////////////////////////////////////////////////////////////////
123// Helper Functions
124///////////////////////////////////////////////////////////////////////////////
125
126/**
127 * Generates an Paillier private/public keyset and extracts the values using libgrcypt only
128 */
129static void
130generate_keyset ()
131{
132 gcry_sexp_t gen_parms;
133 gcry_sexp_t key;
134 gcry_sexp_t tmp_sexp;
135 gcry_mpi_t p;
136 gcry_mpi_t q;
137 gcry_mpi_t tmp1;
138 gcry_mpi_t tmp2;
139 gcry_mpi_t gcd;
140
141 size_t erroff = 0;
142
143 // we can still use the RSA keygen for generating p,q,n, but using e is pointless.
144 GNUNET_assert (0 == gcry_sexp_build (&gen_parms, &erroff,
145 "(genkey(rsa(nbits %d)(rsa-use-e 3:257)))",
146 KEYBITS));
147
148 GNUNET_assert (0 == gcry_pk_genkey (&key, gen_parms));
149 gcry_sexp_release (gen_parms);
150
151 // get n and d of our publickey as MPI
152 tmp_sexp = gcry_sexp_find_token (key, "n", 0);
153 GNUNET_assert (tmp_sexp);
154 my_n = gcry_sexp_nth_mpi (tmp_sexp, 1, GCRYMPI_FMT_USG);
155 gcry_sexp_release (tmp_sexp);
156 tmp_sexp = gcry_sexp_find_token (key, "p", 0);
157 GNUNET_assert (tmp_sexp);
158 p = gcry_sexp_nth_mpi (tmp_sexp, 1, GCRYMPI_FMT_USG);
159 gcry_sexp_release (tmp_sexp);
160 tmp_sexp = gcry_sexp_find_token (key, "q", 0);
161 GNUNET_assert (tmp_sexp);
162 q = gcry_sexp_nth_mpi (tmp_sexp, 1, GCRYMPI_FMT_USG);
163 gcry_sexp_release (key);
164
165 tmp1 = gcry_mpi_new (0);
166 tmp2 = gcry_mpi_new (0);
167 gcd = gcry_mpi_new (0);
168 my_g = gcry_mpi_new (0);
169 my_mu = gcry_mpi_new (0);
170 my_nsquare = gcry_mpi_new (0);
171 my_lambda = gcry_mpi_new (0);
172
173 // calculate lambda
174 // lambda = \frac{(p-1)*(q-1)}{gcd(p-1,q-1)}
175 gcry_mpi_sub_ui (tmp1, p, 1);
176 gcry_mpi_sub_ui (tmp2, q, 1);
177 gcry_mpi_gcd (gcd, tmp1, tmp2);
178 gcry_mpi_set (my_lambda, tmp1);
179 gcry_mpi_mul (my_lambda, my_lambda, tmp2);
180 gcry_mpi_div (my_lambda, NULL, my_lambda, gcd, 0);
181
182 // generate a g
183 gcry_mpi_mul (my_nsquare, my_n, my_n);
184 do
185 {
186 // find a matching g
187 do
188 {
189 gcry_mpi_randomize (my_g, KEYBITS * 2, GCRY_WEAK_RANDOM);
190 // g must be smaller than n^2
191 if (0 >= gcry_mpi_cmp (my_g, my_nsquare))
192 continue;
193
194 // g must have gcd == 1 with n^2
195 gcry_mpi_gcd (gcd, my_g, my_nsquare);
196 }
197 while (gcry_mpi_cmp_ui (gcd, 1));
198
199 // is this a valid g?
200 // if so, gcd(((g^lambda mod n^2)-1 )/n, n) = 1
201 gcry_mpi_powm (tmp1, my_g, my_lambda, my_nsquare);
202 gcry_mpi_sub_ui (tmp1, tmp1, 1);
203 gcry_mpi_div (tmp1, NULL, tmp1, my_n, 0);
204 gcry_mpi_gcd (gcd, tmp1, my_n);
205 }
206 while (gcry_mpi_cmp_ui (gcd, 1));
207
208 // calculate our mu based on g and n.
209 // mu = (((g^lambda mod n^2)-1 )/n)^-1 mod n
210 gcry_mpi_invm (my_mu, tmp1, my_n);
211
212 GNUNET_assert (0 == gcry_sexp_build (&key, &erroff,
213 "(public-key (paillier (n %M)(g %M)))",
214 my_n, my_g));
215
216 // get the length of this sexpression
217 my_pubkey_external_length = gcry_sexp_sprint (key,
218 GCRYSEXP_FMT_CANON,
219 NULL,
220 UINT16_MAX);
221
222 GNUNET_assert (my_pubkey_external_length > 0);
223 my_pubkey_external = GNUNET_malloc (my_pubkey_external_length);
224
225 // convert the sexpression to canonical format
226 gcry_sexp_sprint (key,
227 GCRYSEXP_FMT_CANON,
228 my_pubkey_external,
229 my_pubkey_external_length);
230
231 gcry_sexp_release (key);
232
233 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Generated key set with key length %d bits.\n"), KEYBITS);
234}
235
236
237/**
238 * If target != size, move target bytes to the
239 * end of the size-sized buffer and zero out the
240 * first target-size bytes.
241 *
242 * @param buf original buffer
243 * @param size number of bytes in the buffer
244 * @param target target size of the buffer
245 */
246static void
247adjust (unsigned char *buf, size_t size, size_t target)
248{
249 if (size < target)
250 {
251 memmove (&buf[target - size], buf, size);
252 memset (buf, 0, target - size);
253 }
254}
255
256
257/**
258 * encrypts an element using the paillier crypto system
259 *
260 * @param c ciphertext (output)
261 * @param m plaintext
262 * @param g the public base
263 * @param r random base (optional) gets generated and if not NULL but uninitialized
264 * @param n the module from which which r is chosen (Z*_n)
265 * @param n_square the module for encryption, for performance reasons.
266 */
267static void
268encrypt_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)
269{
270#ifndef DISABLE_CRYPTO
271 gcry_mpi_t tmp;
272 int release_r = GNUNET_NO;
273
274 GNUNET_assert (tmp = gcry_mpi_new (0));
275 if (NULL == r)
276 {
277 GNUNET_assert (r = gcry_mpi_new (0));
278 release_r = GNUNET_YES;
279
280 while (0 <= gcry_mpi_cmp (r, n) || 0 >= gcry_mpi_cmp_ui (r, 1))
281 {
282 gcry_mpi_randomize (r, KEYBITS, GCRY_WEAK_RANDOM);
283 // r must be 1 < r < n
284 }
285 }
286
287
288 gcry_mpi_powm (c, g, m, n_square);
289 gcry_mpi_powm (tmp, r, n, n_square);
290 gcry_mpi_mulm (c, tmp, c, n_square);
291
292 gcry_mpi_release (tmp);
293 if (GNUNET_YES == release_r)
294 gcry_mpi_release (r);
295#else
296 gcry_mpi_set (c, m);
297#endif
298}
299
300
301/**
302 * decrypts an element using the paillier crypto system
303 *
304 * @param m plaintext (output)
305 * @param c the ciphertext
306 * @param mu the modifier to correct encryption
307 * @param lambda the private exponent
308 * @param n the outer module for decryption
309 * @param n_square the inner module for decryption
310 */
311static void
312decrypt_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)
313{
314#ifndef DISABLE_CRYPTO
315 gcry_mpi_powm (m, c, lambda, n_square);
316 gcry_mpi_sub_ui (m, m, 1);
317 gcry_mpi_div (m, NULL, m, n, 0);
318 gcry_mpi_mulm (m, m, mu, n);
319#else
320 gcry_mpi_set (m, c);
321#endif
322}
323
324
325/**
326 * computes the square sum over a vector of a given length.
327 *
328 * @param vector the vector to encrypt
329 * @param length the length of the vector
330 * @return an MPI value containing the calculated sum, never NULL
331 */
332static gcry_mpi_t
333compute_square_sum (gcry_mpi_t * vector, uint16_t length)
334{
335 gcry_mpi_t elem;
336 gcry_mpi_t sum;
337 int32_t i;
338
339 GNUNET_assert (sum = gcry_mpi_new (0));
340 GNUNET_assert (elem = gcry_mpi_new (0));
341
342 // calculare E(sum (ai ^ 2), publickey)
343 for (i = 0; i < length; i++)
344 {
345 gcry_mpi_mul (elem, vector[i], vector[i]);
346 gcry_mpi_add (sum, sum, elem);
347 }
348 gcry_mpi_release (elem);
349
350 return sum;
351}
352
353
354/**
355 * Primitive callback for copying over a message, as they
356 * usually are too complex to be handled in the callback itself.
357 * clears a session-callback, if a session was handed over and the transmit handle was stored
358 *
359 * @param cls the message object
360 * @param size the size of the buffer we got
361 * @param buf the buffer to copy the message to
362 * @return 0 if we couldn't copy, else the size copied over
363 */
364static size_t
365do_send_message (void *cls, size_t size, void *buf)
366{
367 struct MessageObject * info = cls;
368 struct GNUNET_MessageHeader * msg;
369 size_t written = 0;
370
371 GNUNET_assert (info);
372 msg = info->msg;
373 GNUNET_assert (msg);
374 GNUNET_assert (buf);
375
376 if (ntohs (msg->size) == size)
377 {
378 memcpy (buf, msg, size);
379 written = size;
380 }
381
382 // reset the transmit handle, if necessary
383 if (info->transmit_handle)
384 *info->transmit_handle = NULL;
385
386 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Sent a message of type %hu.\n"), ntohs (msg->type));
387 GNUNET_free(msg);
388 GNUNET_free(info);
389 return written;
390}
391
392
393/**
394 * initializes a new vector with fresh MPI values (=0) of a given length
395 *
396 * @param length of the vector to create
397 * @return the initialized vector, never NULL
398 */
399static gcry_mpi_t *
400initialize_mpi_vector (uint16_t length)
401{
402 uint32_t i;
403 gcry_mpi_t * output = GNUNET_malloc (sizeof (gcry_mpi_t) * length);
404
405 for (i = 0; i < length; i++)
406 GNUNET_assert (NULL != (output[i] = gcry_mpi_new (0)));
407 return output;
408}
409
410
411/**
412 * permutes an MPI vector according to the given permutation vector
413 *
414 * @param vector the vector to permuted
415 * @param perm the permutation to use
416 * @param length the length of the vectors
417 * @return the permuted vector (same as input), never NULL
418 */
419static gcry_mpi_t *
420permute_vector (gcry_mpi_t * vector,
421 unsigned int * perm,
422 uint32_t length)
423{
424 gcry_mpi_t tmp[length];
425 uint32_t i;
426
427 GNUNET_assert (length > 0);
428
429 // backup old layout
430 memcpy (tmp, vector, length * sizeof (gcry_mpi_t));
431
432 // permute vector according to given
433 for (i = 0; i < length; i++)
434 vector[i] = tmp[perm[i]];
435
436 return vector;
437}
438
439
440/**
441 * Populate a vector with random integer values and convert them to
442 *
443 * @param length the length of the vector we must generate
444 * @return an array of MPI values with random values
445 */
446static gcry_mpi_t *
447generate_random_vector (uint16_t length)
448{
449 gcry_mpi_t * random_vector;
450 int32_t value;
451 uint32_t i;
452
453 random_vector = initialize_mpi_vector (length);
454 for (i = 0; i < length; i++)
455 {
456 value = (int32_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX);
457
458 // long to gcry_mpi_t
459 if (value < 0)
460 gcry_mpi_sub_ui (random_vector[i],
461 random_vector[i],
462 -value);
463 else
464 random_vector[i] = gcry_mpi_set_ui (random_vector[i], value);
465 }
466
467 return random_vector;
468}
469
470
471/**
472 * Finds a not terminated client/service session in the
473 * given DLL based on session key, element count and state.
474 *
475 * @param tail - the tail of the DLL
476 * @param my - the session to compare it to
477 * @return a pointer to a matching session,
478 * else NULL
479 */
480static struct ServiceSession *
481find_matching_session (struct ServiceSession * tail,
482 struct GNUNET_HashCode * key,
483 uint16_t element_count,
484 enum SessionState * state,
485 const struct GNUNET_PeerIdentity * peerid)
486{
487 struct ServiceSession * curr;
488
489 for (curr = tail; NULL != curr; curr = curr->prev)
490 {
491 // if the key matches, and the element_count is same
492 if ((!memcmp (&curr->key, key, sizeof (struct GNUNET_HashCode)))
493 && (curr->element_count == element_count))
494 {
495 // if incoming state is NULL OR is same as state of the queued request
496 if ((NULL == state) || (curr->state == *state))
497 {
498 // if peerid is NULL OR same as the peer Id in the queued request
499 if ((NULL == peerid)
500 || (!memcmp (&curr->peer, peerid, sizeof (struct GNUNET_PeerIdentity))))
501 // matches and is not an already terminated session
502 return curr;
503 }
504 }
505 }
506
507 return NULL;
508}
509
510
511static void
512destroy_tunnel (void *cls,
513 const struct GNUNET_SCHEDULER_TaskContext *tc)
514{
515 struct ServiceSession * session = cls;
516
517 if (session->tunnel)
518 {
519 GNUNET_MESH_tunnel_destroy (session->tunnel);
520 session->tunnel = NULL;
521 }
522 session->service_transmit_handle = NULL;
523 // we need to set this to NULL so there is no problem with double-cancel later on.
524}
525
526
527static void
528free_session (struct ServiceSession * session)
529{
530 int i;
531
532 if (FINALIZED != session->state)
533 {
534 if (session->a)
535 {
536 for (i = 0; i < session->used_element_count; i++)
537 gcry_mpi_release (session->a[i]);
538
539 GNUNET_free (session->a);
540 }
541 if (session->product)
542 gcry_mpi_release (session->product);
543
544 if (session->remote_pubkey)
545 gcry_sexp_release (session->remote_pubkey);
546
547 GNUNET_free_non_null (session->vector);
548 }
549
550 GNUNET_free (session);
551}
552///////////////////////////////////////////////////////////////////////////////
553// Event and Message Handlers
554///////////////////////////////////////////////////////////////////////////////
555
556
557/**
558 * A client disconnected.
559 *
560 * Remove the associated session(s), release datastructures
561 * and cancel pending outgoing transmissions to the client.
562 * if the session has not yet completed, we also cancel Alice's request to Bob.
563 *
564 * @param cls closure, NULL
565 * @param client identification of the client
566 */
567static void
568handle_client_disconnect (void *cls,
569 struct GNUNET_SERVER_Client
570 * client)
571{
572 struct ServiceSession * elem;
573 struct ServiceSession * next;
574
575 // start from the tail, old stuff will be there...
576 for (elem = from_client_head; NULL != elem; elem = next)
577 {
578 next = elem->next;
579 if (elem->client != client)
580 continue;
581
582 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Client (%p) disconnected from us.\n"), client);
583 GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, elem);
584
585 if (!(elem->role == BOB && elem->state == FINALIZED))
586 {
587 //we MUST terminate any client message underway
588 if (elem->service_transmit_handle && elem->tunnel)
589 GNUNET_MESH_notify_transmit_ready_cancel (elem->service_transmit_handle);
590 if (elem->tunnel && elem->state == WAITING_FOR_RESPONSE_FROM_SERVICE)
591 destroy_tunnel (elem, NULL);
592 }
593 free_session (elem);
594 }
595}
596
597
598/**
599 * Notify the client that the session has succeeded or failed completely.
600 * This message gets sent to
601 * * alice's client if bob disconnected or to
602 * * bob's client if the operation completed or alice disconnected
603 *
604 * @param client_session the associated client session
605 * @return GNUNET_NO, if we could not notify the client
606 * GNUNET_YES if we notified it.
607 */
608static void
609prepare_client_end_notification (void * cls,
610 const struct GNUNET_SCHEDULER_TaskContext * tc)
611{
612 struct ServiceSession * session = cls;
613 struct GNUNET_VECTORPRODUCT_client_response * msg;
614 struct MessageObject * msg_obj;
615
616 GNUNET_assert (NULL != session);
617
618 msg = GNUNET_new (struct GNUNET_VECTORPRODUCT_client_response);
619 msg->header.type = htons (GNUNET_MESSAGE_TYPE_VECTORPRODUCT_SERVICE_TO_CLIENT);
620 memcpy (&msg->key, &session->key, sizeof (struct GNUNET_HashCode));
621 memcpy (&msg->peer, &session->peer, sizeof ( struct GNUNET_PeerIdentity));
622 msg->header.size = htons (sizeof (struct GNUNET_VECTORPRODUCT_client_response));
623 // 0 size and the first char in the product is 0, which should never be zero if encoding is used.
624 msg->product_length = htonl (0);
625
626 msg_obj = GNUNET_malloc (sizeof (struct MessageObject));
627 msg_obj->msg = (struct GNUNET_MessageHeader *) msg;
628 msg_obj->transmit_handle = NULL; // do not reset the transmit handle, please
629
630 //transmit this message to our client
631 session->client_transmit_handle =
632 GNUNET_SERVER_notify_transmit_ready (session->client,
633 sizeof (struct GNUNET_VECTORPRODUCT_client_response),
634 GNUNET_TIME_UNIT_FOREVER_REL,
635 &do_send_message,
636 msg_obj);
637
638
639 // if we could not even queue our request, something is wrong
640 if ( ! session->client_transmit_handle)
641 {
642
643 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);
644 // usually gets freed by do_send_message
645 GNUNET_free (msg_obj);
646 GNUNET_free (msg);
647 }
648 else
649 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Sending session-end notification to client (%p) for session %s\n"), &session->client, GNUNET_h2s (&session->key));
650
651 free_session(session);
652}
653
654
655/**
656 * Bob executes:
657 * generates the response message to be sent to alice after computing
658 * the values (1), (2), S and S'
659 * (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)})$
660 * (2)[]: $E_A(a_{\pi'(i)}) \otimes E_A(- r_{\pi'(i)}) &= E_A(a_{\pi'(i)} - r_{\pi'(i)})$
661 * S: $S := E_A(\sum (r_i + b_i)^2)$
662 * S': $S' := E_A(\sum r_i^2)$
663 *
664 * @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)})$
665 * @param kq (2)[]: $E_A(a_{\pi'(i)}) \otimes E_A(- r_{\pi'(i)}) &= E_A(a_{\pi'(i)} - r_{\pi'(i)})$
666 * @param s S: $S := E_A(\sum (r_i + b_i)^2)$
667 * @param stick S': $S' := E_A(\sum r_i^2)$
668 * @param request the associated requesting session with alice
669 * @param response the associated responder session with bob's client
670 * @return GNUNET_SYSERR if the function was called with NULL parameters or if there was an error
671 * GNUNET_NO if we could not send our message
672 * GNUNET_OK if the operation succeeded
673 */
674static int
675prepare_service_response (gcry_mpi_t * kp,
676 gcry_mpi_t * kq,
677 gcry_mpi_t s,
678 gcry_mpi_t stick,
679 struct ServiceSession * request,
680 struct ServiceSession * response)
681{
682 struct GNUNET_VECTORPRODUCT_service_response * msg;
683 uint16_t msg_length = 0;
684 unsigned char * current = NULL;
685 unsigned char * element_exported = NULL;
686 size_t element_length = 0;
687 int i;
688
689 GNUNET_assert (request);
690
691 msg_length = sizeof (struct GNUNET_VECTORPRODUCT_service_response)
692 + 2 * request->used_element_count * PAILLIER_ELEMENT_LENGTH // kp, kq
693 + 2 * PAILLIER_ELEMENT_LENGTH; // s, stick
694
695 msg = GNUNET_malloc (msg_length);
696 GNUNET_assert (msg);
697
698 msg->header.type = htons (GNUNET_MESSAGE_TYPE_VECTORPRODUCT_BOB_TO_ALICE);
699 msg->header.size = htons (msg_length);
700 msg->element_count = htons (request->element_count);
701 msg->used_element_count = htons (request->used_element_count);
702 memcpy (&msg->key, &request->key, sizeof (struct GNUNET_HashCode));
703 current = (unsigned char *) &msg[1];
704
705 // 4 times the same logics with slight variations.
706 // doesn't really justify having 2 functions for that
707 // so i put it into blocks to enhance readability
708 // convert s
709 {
710 element_exported = GNUNET_malloc (PAILLIER_ELEMENT_LENGTH);
711 GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG,
712 element_exported, PAILLIER_ELEMENT_LENGTH,
713 &element_length,
714 s));
715 adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH);
716 memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH);
717 GNUNET_free (element_exported);
718 current += PAILLIER_ELEMENT_LENGTH;
719 }
720
721 // convert stick
722 {
723 element_exported = GNUNET_malloc (PAILLIER_ELEMENT_LENGTH);
724 GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG,
725 element_exported, PAILLIER_ELEMENT_LENGTH,
726 &element_length,
727 stick));
728 adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH);
729 memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH);
730 GNUNET_free (element_exported);
731 current += PAILLIER_ELEMENT_LENGTH;
732 }
733
734 // convert kp[]
735 for (i = 0; i < request->used_element_count; i++)
736 {
737 element_exported = GNUNET_malloc (PAILLIER_ELEMENT_LENGTH);
738 GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG,
739 element_exported, PAILLIER_ELEMENT_LENGTH,
740 &element_length,
741 kp[i]));
742 adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH);
743 memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH);
744 GNUNET_free (element_exported);
745 current += PAILLIER_ELEMENT_LENGTH;
746 }
747
748
749 // convert kq[]
750 for (i = 0; i < request->used_element_count; i++)
751 {
752 element_exported = GNUNET_malloc (PAILLIER_ELEMENT_LENGTH);
753 GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG,
754 element_exported, PAILLIER_ELEMENT_LENGTH,
755 &element_length,
756 kq[i]));
757 adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH);
758 memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH);
759 GNUNET_free (element_exported);
760 current += PAILLIER_ELEMENT_LENGTH;
761 }
762
763 if (GNUNET_SERVER_MAX_MESSAGE_SIZE >= msg_length)
764 {
765 struct MessageObject * msg_obj;
766
767 msg_obj = GNUNET_new (struct MessageObject);
768 msg_obj->msg = (struct GNUNET_MessageHeader *) msg;
769 msg_obj->transmit_handle = (void *) &request->service_transmit_handle; //and reset the transmit handle
770 request->service_transmit_handle =
771 GNUNET_MESH_notify_transmit_ready (request->tunnel,
772 GNUNET_YES,
773 GNUNET_TIME_UNIT_FOREVER_REL,
774 &request->peer, //must be specified, we are a slave/participant/non-owner
775 msg_length,
776 &do_send_message,
777 msg_obj);
778 // we don't care if it could be send or not. either way, the session is over for us.
779 request->state = FINALIZED;
780 response->state = FINALIZED;
781 }
782 else
783 {
784 // TODO FEATURE: fallback to fragmentation, in case the message is too long
785 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Message too large, fragmentation is currently not supported!)\n"));
786 }
787
788 //disconnect our client
789 if ( ! request->service_transmit_handle)
790 {
791 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Could not send service-response message via mesh!)\n"));
792 GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, response);
793 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
794 &prepare_client_end_notification,
795 response);
796 return GNUNET_NO;
797 }
798 return GNUNET_OK;
799}
800
801
802/**
803 * executed by bob:
804 * compute the values
805 * (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)})$
806 * (2)[]: $E_A(a_{\pi'(i)}) \otimes E_A(- r_{\pi'(i)}) &= E_A(a_{\pi'(i)} - r_{\pi'(i)})$
807 * S: $S := E_A(\sum (r_i + b_i)^2)$
808 * S': $S' := E_A(\sum r_i^2)$
809 *
810 * @param request the requesting session + bob's requesting peer
811 * @param response the responding session + bob's client handle
812 * @return GNUNET_SYSERR if the computation failed
813 * GNUNET_OK if everything went well.
814 */
815static int
816compute_service_response (struct ServiceSession * request,
817 struct ServiceSession * response)
818{
819 int i, j, ret = GNUNET_SYSERR;
820 unsigned int * p;
821 unsigned int * q;
822 uint16_t count;
823 gcry_mpi_t * r = NULL;
824 gcry_mpi_t * kp = NULL;
825 gcry_mpi_t * kq = NULL;
826 gcry_mpi_t * b;
827 gcry_mpi_t * ap;
828 gcry_mpi_t * aq;
829 gcry_mpi_t * bp;
830 gcry_mpi_t * bq;
831 gcry_mpi_t * rp;
832 gcry_mpi_t * rq;
833 gcry_mpi_t s = NULL;
834 gcry_mpi_t stick = NULL;
835 gcry_mpi_t remote_n = NULL;
836 gcry_mpi_t remote_nsquare;
837 gcry_mpi_t remote_g = NULL;
838 gcry_sexp_t tmp_exp;
839 uint32_t value;
840
841 GNUNET_assert (request != NULL && response != NULL);
842 count = request->used_element_count;
843
844 b = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
845 ap = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
846 bp = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
847 aq = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
848 bq = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
849 rp = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
850 rq = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
851
852 // convert responder session to from long to mpi
853 for (i = 0, j = 0; i < response->element_count && j < count; i++)
854 {
855 if (request->mask[i / 8] & (1 << (i % 8)))
856 {
857 value = response->vector[i] >= 0 ? response->vector[i] : -response->vector[i];
858 // long to gcry_mpi_t
859 if (0 > response->vector[i])
860 {
861 b[j] = gcry_mpi_new (0);
862 gcry_mpi_sub_ui (b[j], b[j], value);
863 }
864 else
865 {
866 b[j] = gcry_mpi_set_ui (NULL, value);
867 }
868 j++;
869 }
870 }
871 GNUNET_free (response->vector);
872 response->vector = NULL;
873
874 tmp_exp = gcry_sexp_find_token (request->remote_pubkey, "n", 0);
875 if ( ! tmp_exp)
876 {
877 GNUNET_break_op (0);
878 gcry_sexp_release (request->remote_pubkey);
879 request->remote_pubkey = NULL;
880 goto except;
881 }
882 remote_n = gcry_sexp_nth_mpi (tmp_exp, 1, GCRYMPI_FMT_USG);
883 if ( ! remote_n)
884 {
885 GNUNET_break (0);
886 gcry_sexp_release (tmp_exp);
887 goto except;
888 }
889 remote_nsquare = gcry_mpi_new (KEYBITS + 1);
890 gcry_mpi_mul (remote_nsquare, remote_n, remote_n);
891 gcry_sexp_release (tmp_exp);
892 tmp_exp = gcry_sexp_find_token (request->remote_pubkey, "g", 0);
893 gcry_sexp_release (request->remote_pubkey);
894 request->remote_pubkey = NULL;
895 if ( ! tmp_exp)
896 {
897 GNUNET_break_op (0);
898 gcry_mpi_release (remote_n);
899 goto except;
900 }
901 remote_g = gcry_sexp_nth_mpi (tmp_exp, 1, GCRYMPI_FMT_USG);
902 if ( ! remote_g)
903 {
904 GNUNET_break (0);
905 gcry_mpi_release (remote_n);
906 gcry_sexp_release (tmp_exp);
907 goto except;
908 }
909 gcry_sexp_release (tmp_exp);
910
911 // generate r, p and q
912 r = generate_random_vector (count);
913 p = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, count);
914 q = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, count);
915 //initialize the result vectors
916 kp = initialize_mpi_vector (count);
917 kq = initialize_mpi_vector (count);
918
919 // copy the REFERNCES of a, b and r into aq and bq. we will not change
920 // those values, thus we can work with the references
921 memcpy (ap, request->a, sizeof (gcry_mpi_t) * count);
922 memcpy (aq, request->a, sizeof (gcry_mpi_t) * count);
923 memcpy (bp, b, sizeof (gcry_mpi_t) * count);
924 memcpy (bq, b, sizeof (gcry_mpi_t) * count);
925 memcpy (rp, r, sizeof (gcry_mpi_t) * count);
926 memcpy (rq, r, sizeof (gcry_mpi_t) * count);
927
928 // generate p and q permutations for a, b and r
929 GNUNET_assert (permute_vector (ap, p, count));
930 GNUNET_assert (permute_vector (bp, p, count));
931 GNUNET_assert (permute_vector (rp, p, count));
932 GNUNET_assert (permute_vector (aq, q, count));
933 GNUNET_assert (permute_vector (bq, q, count));
934 GNUNET_assert (permute_vector (rq, q, count));
935
936 // encrypt the element
937 // for the sake of readability I decided to have dedicated permutation
938 // vectors, which get rid of all the lookups in p/q.
939 // however, ap/aq are not absolutely necessary but are just abstraction
940 // Calculate Kp = E(a_pi) + E(-r_pi - b_pi)
941 for (i = 0; i < count; i++)
942 {
943 // E(-r_pi - b_pi)
944 gcry_mpi_sub (kp[i], kp[i], rp[i]);
945 gcry_mpi_sub (kp[i], kp[i], bp[i]);
946 encrypt_element (kp[i], kp[i], NULL, remote_g, remote_n, remote_nsquare);
947
948 // E(-r_pi - b_pi) * E(a_pi) == E(a + (-r -b))
949 //gcry_mpi_mulm (kp[i], kp[i], ap[i], remote_nsquare);
950 gcry_mpi_add (kp[i], kp[i], ap[i]);
951 }
952 GNUNET_free (ap);
953 GNUNET_free (bp);
954 GNUNET_free (rp);
955
956 // Calculate Kq = E(a_qi) + E( -r_qi)
957 for (i = 0; i < count; i++)
958 {
959 // E(-r_qi)
960 gcry_mpi_sub (kq[i], kq[i], rq[i]);
961 encrypt_element (kq[i], kq[i], NULL, remote_g, remote_n, remote_nsquare);
962
963 // E(-r_qi) * E(a_qi) == E(aqi + (- rqi))
964 //gcry_mpi_mulm (kq[i], kq[i], aq[i], remote_nsquare);
965 gcry_mpi_add (kq[i], kq[i], aq[i]);
966 }
967 GNUNET_free (aq);
968 GNUNET_free (bq);
969 GNUNET_free (rq);
970
971 // Calculate S' = E(SUM( r_i^2 ))
972 stick = compute_square_sum (r, count);
973 encrypt_element (stick, stick, NULL, remote_g, remote_n, remote_nsquare);
974
975 // Calculate S = E(SUM( (r_i + b_i)^2 ))
976 for (i = 0; i < count; i++)
977 {
978 gcry_mpi_add (r[i], r[i], b[i]);
979 }
980 s = compute_square_sum (r, count);
981 encrypt_element (s, s, NULL, remote_g, remote_n, remote_nsquare);
982 gcry_mpi_release (remote_n);
983 gcry_mpi_release (remote_g);
984 gcry_mpi_release (remote_nsquare);
985
986 // release r and tmp
987 for (i = 0; i < count; i++)
988 // rp, rq, aq, ap, bp, bq are released along with a, r, b respectively, (a and b are handled at except:)
989 gcry_mpi_release (r[i]);
990
991 // copy the Kp[], Kq[], S and Stick into a new message
992 if (GNUNET_YES != prepare_service_response (kp, kq, s, stick, request, response))
993 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Computation of values for alice failed!\n"));
994 else
995 ret = GNUNET_OK;
996
997 for (i = 0; i < count; i++)
998 {
999 gcry_mpi_release (kq[i]);
1000 gcry_mpi_release (kp[i]);
1001 }
1002
1003 gcry_mpi_release (s);
1004 gcry_mpi_release (stick);
1005
1006except:
1007 for (i = 0; i < count; i++)
1008 {
1009 gcry_mpi_release (b[i]);
1010 gcry_mpi_release (request->a[i]);
1011 }
1012
1013 GNUNET_free (b);
1014 GNUNET_free (request->a);
1015 request->a = NULL;
1016
1017 return ret;
1018}
1019
1020
1021/**
1022 * Executed by Alice, fills in a service-request message and sends it to the given peer
1023 *
1024 * @param session the session associated with this request, then also holds the CORE-handle
1025 * @return GNUNET_SYSERR if we could not send the message
1026 * GNUNET_NO if the message was too large
1027 * GNUNET_OK if we sent it
1028 */
1029static void
1030prepare_service_request (void *cls,
1031 const struct GNUNET_PeerIdentity * peer,
1032 const struct GNUNET_ATS_Information * atsi)
1033{
1034 struct ServiceSession * session = cls;
1035 unsigned char * current;
1036 struct GNUNET_VECTORPRODUCT_service_request * msg;
1037 struct MessageObject * msg_obj;
1038 unsigned int i;
1039 unsigned int j;
1040 uint16_t msg_length;
1041 size_t element_length = 0; //gets initialized by gcry_mpi_print, but the compiler doesn't know that
1042 gcry_mpi_t a;
1043 gcry_mpi_t r;
1044 uint32_t value;
1045
1046 GNUNET_assert (NULL != cls);
1047 GNUNET_assert (NULL != peer);
1048 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Successfully created new tunnel to peer (%s)!\n"), GNUNET_i2s (peer));
1049
1050 msg_length = sizeof (struct GNUNET_VECTORPRODUCT_service_request)
1051 + session->used_element_count * PAILLIER_ELEMENT_LENGTH
1052 + session->mask_length
1053 + my_pubkey_external_length;
1054
1055 if (GNUNET_SERVER_MAX_MESSAGE_SIZE < sizeof (struct GNUNET_VECTORPRODUCT_service_request)
1056 + session->used_element_count * PAILLIER_ELEMENT_LENGTH
1057 + session->mask_length
1058 + my_pubkey_external_length)
1059 {
1060 // TODO FEATURE: fallback to fragmentation, in case the message is too long
1061 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Message too large, fragmentation is currently not supported!\n"));
1062 GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, session);
1063 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
1064 &prepare_client_end_notification,
1065 session);
1066 return;
1067 }
1068 msg = GNUNET_malloc (msg_length);
1069
1070 msg->header.type = htons (GNUNET_MESSAGE_TYPE_VECTORPRODUCT_ALICE_TO_BOB);
1071 memcpy (&msg->key, &session->key, sizeof (struct GNUNET_HashCode));
1072 msg->mask_length = htons (session->mask_length);
1073 msg->pk_length = htons (my_pubkey_external_length);
1074 msg->used_element_count = htons (session->used_element_count);
1075 msg->element_count = htons (session->element_count);
1076 msg->header.size = htons (msg_length);
1077
1078 // fill in the payload
1079 current = (unsigned char *) &msg[1];
1080 // copy over the mask
1081 memcpy (current, session->mask, session->mask_length);
1082 // copy over our public key
1083 current += session->mask_length;
1084 memcpy (current, my_pubkey_external, my_pubkey_external_length);
1085 current += my_pubkey_external_length;
1086
1087 // now copy over the element vector
1088 session->a = GNUNET_malloc (sizeof (gcry_mpi_t) * session->used_element_count);
1089 a = gcry_mpi_new (KEYBITS * 2);
1090 r = gcry_mpi_new (KEYBITS * 2);
1091 // encrypt our vector and generate string representations
1092 for (i = 0, j = 0; i < session->element_count; i++)
1093 {
1094 // if this is a used element...
1095 if (session->mask[i / 8] & 1 << (i % 8))
1096 {
1097 unsigned char * element_exported = GNUNET_malloc (PAILLIER_ELEMENT_LENGTH);
1098 value = session->vector[i] >= 0 ? session->vector[i] : -session->vector[i];
1099
1100 // long to gcry_mpi_t
1101 if (session->vector[i] < 0)
1102 {
1103 a = gcry_mpi_set_ui (NULL, 0);
1104 gcry_mpi_sub_ui (a, a, value);
1105 }
1106 else
1107 a = gcry_mpi_set_ui (NULL, value);
1108
1109 // multiply with a given factor to avoid disclosing 1
1110 session->a[j++] = gcry_mpi_set (NULL, a);
1111 encrypt_element (a, a, r, my_g, my_n, my_nsquare);
1112
1113 // get representation as string
1114 // we always supply some value, so gcry_mpi_print fails only if it can't reserve memory
1115 GNUNET_assert ( ! gcry_mpi_print (GCRYMPI_FMT_USG,
1116 element_exported, PAILLIER_ELEMENT_LENGTH,
1117 &element_length,
1118 a));
1119
1120 // move buffer content to the end of the buffer so it can easily be read by libgcrypt. also this now has fixed size
1121 adjust (element_exported, element_length, PAILLIER_ELEMENT_LENGTH);
1122
1123 // copy over to the message
1124 memcpy (current, element_exported, PAILLIER_ELEMENT_LENGTH);
1125 current += PAILLIER_ELEMENT_LENGTH;
1126 }
1127 }
1128 gcry_mpi_release (a);
1129 gcry_mpi_release (r);
1130
1131 msg_obj = GNUNET_malloc (sizeof (struct MessageObject));
1132 msg_obj->msg = (struct GNUNET_MessageHeader *) msg;
1133 msg_obj->transmit_handle = (void *) &session->service_transmit_handle; //and reset the transmit handle
1134 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transmitting service request.\n"));
1135
1136 //transmit via mesh messaging
1137 session->state = WAITING_FOR_RESPONSE_FROM_SERVICE;
1138 session->service_transmit_handle = GNUNET_MESH_notify_transmit_ready (session->tunnel, GNUNET_YES,
1139 GNUNET_TIME_UNIT_FOREVER_REL,
1140 peer, //multicast to all targets, maybe useful in the future
1141 msg_length,
1142 &do_send_message,
1143 msg_obj);
1144 if ( ! session->service_transmit_handle)
1145 {
1146 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not send mutlicast message to tunnel!\n"));
1147 GNUNET_free (msg_obj);
1148 GNUNET_free (msg);
1149 GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, session);
1150 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
1151 &prepare_client_end_notification,
1152 session);
1153 return;
1154 }
1155}
1156
1157
1158/**
1159 * Method called whenever a peer has disconnected from the tunnel.
1160 * Implementations of this callback must NOT call
1161 * GNUNET_MESH_tunnel_destroy immediately, but instead schedule those
1162 * to run in some other task later. However, calling
1163 * "GNUNET_MESH_notify_transmit_ready_cancel" is allowed.
1164 *
1165 * @param cls closure
1166 * @param peer peer identity the tunnel stopped working with
1167 */
1168static void
1169tunnel_peer_disconnect_handler (void *cls, const struct GNUNET_PeerIdentity * peer)
1170{
1171 // as we have only one peer connected in each session, just remove the session and say good bye
1172 struct ServiceSession * session = cls;
1173 struct ServiceSession * curr;
1174 GNUNET_assert(cls);
1175 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Peer (%s) disconnected from our tunnel!\n"), GNUNET_i2s (peer));
1176
1177 if ((session->role == ALICE) && (FINALIZED != session->state) && ( ! do_shutdown))
1178 {
1179 for (curr = from_client_head; NULL != curr; curr = curr->next)
1180 if (curr == session)
1181 {
1182 GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, session);
1183 break;
1184 }
1185 GNUNET_SCHEDULER_add_now (&destroy_tunnel,
1186 session);
1187 // if this happened before we received the answer, we must terminate the session
1188 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
1189 &prepare_client_end_notification,
1190 session);
1191 }
1192}
1193
1194
1195/**
1196 * Handler for a client request message.
1197 * Can either be type A or B
1198 * A: request-initiation to compute a scalar product with a peer
1199 * B: response role, keep the values + session and wait for a matching session or process a waiting request
1200 *
1201 * @param cls closure
1202 * @param client identification of the client
1203 * @param message the actual message
1204 */
1205static void
1206handle_client_request (void *cls,
1207 struct GNUNET_SERVER_Client *client,
1208 const struct GNUNET_MessageHeader *message)
1209{
1210 struct GNUNET_VECTORPRODUCT_client_request * msg = (struct GNUNET_VECTORPRODUCT_client_request *) message;
1211 struct ServiceSession * session;
1212 uint16_t element_count;
1213 uint16_t mask_length;
1214 uint16_t msg_type;
1215 int32_t * vector;
1216 uint32_t i;
1217
1218 GNUNET_assert (message);
1219
1220 //we need at least a peer and one message id to compare
1221 if (sizeof (struct GNUNET_VECTORPRODUCT_client_request) > ntohs (msg->header.size))
1222 {
1223 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Too short message received from client!\n"));
1224 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1225 return;
1226 }
1227
1228 msg_type = ntohs (msg->header.type);
1229 element_count = ntohs (msg->element_count);
1230 mask_length = ntohs (msg->mask_length);
1231
1232 //sanity check: is the message as long as the message_count fields suggests?
1233 if (( ntohs (msg->header.size) != (sizeof (struct GNUNET_VECTORPRODUCT_client_request) + element_count * sizeof (int32_t) + mask_length))
1234 || (0 == element_count))
1235 {
1236 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Invalid message received from client, session information incorrect!\n"));
1237 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1238 return;
1239 }
1240
1241 // do we have a duplicate session here already?
1242 if (NULL != find_matching_session (from_client_tail,
1243 &msg->key,
1244 element_count,
1245 NULL, NULL))
1246 {
1247 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Duplicate session information received, cannot create new session with key `%s'\n"), GNUNET_h2s (&msg->key));
1248 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1249 return;
1250 }
1251
1252 session = GNUNET_malloc (sizeof (struct ServiceSession));
1253 session->client = client;
1254 session->element_count = element_count;
1255 session->mask_length = mask_length;
1256 // get our transaction key
1257 memcpy (&session->key, &msg->key, sizeof (struct GNUNET_HashCode));
1258 //allocate memory for vector and encrypted vector
1259 session->vector = GNUNET_malloc (sizeof (int32_t) * element_count);
1260 vector = (int32_t *) & msg[1];
1261
1262 if (GNUNET_MESSAGE_TYPE_VECTORPRODUCT_CLIENT_TO_ALICE == msg_type)
1263 {
1264 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Got client-request-session with key %s, preparing tunnel to remote service.\n"), GNUNET_h2s (&session->key));
1265
1266 session->role = ALICE;
1267 // fill in the mask
1268 session->mask = GNUNET_malloc (mask_length);
1269 memcpy (session->mask, &vector[element_count], mask_length);
1270
1271 // copy over the elements
1272 session->used_element_count = 0;
1273 for (i = 0; i < element_count; i++)
1274 {
1275 session->vector[i] = ntohl (vector[i]);
1276 if (session->vector[i] == 0)
1277 session->mask[i / 8] &= ~(1 << (i % 8));
1278 if (session->mask[i / 8] & (1 << (i % 8)))
1279 session->used_element_count++;
1280 }
1281
1282 if ( ! session->used_element_count)
1283 {
1284 GNUNET_break_op (0);
1285 GNUNET_free (session->vector);
1286 GNUNET_free (session->a);
1287 GNUNET_free (session);
1288 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1289 return;
1290 }
1291 //session with ourself makes no sense!
1292 if ( ! memcmp (&msg->peer, &me, sizeof (struct GNUNET_PeerIdentity)))
1293 {
1294 GNUNET_break (0);
1295 GNUNET_free (session->vector);
1296 GNUNET_free (session->a);
1297 GNUNET_free (session);
1298 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1299 return;
1300 }
1301 // get our peer ID
1302 memcpy (&session->peer, &msg->peer, sizeof (struct GNUNET_PeerIdentity));
1303 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Creating new tunnel to for session with key %s.\n"), GNUNET_h2s (&session->key));
1304 GNUNET_CONTAINER_DLL_insert (from_client_head, from_client_tail, session);
1305 session->tunnel = GNUNET_MESH_tunnel_create (my_mesh, session,
1306 prepare_service_request,
1307 tunnel_peer_disconnect_handler,
1308 session);
1309 if ( ! session->tunnel)
1310 {
1311 GNUNET_break (0);
1312 GNUNET_free (session->vector);
1313 GNUNET_free (session->a);
1314 GNUNET_free (session);
1315 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1316 return;
1317 }
1318 GNUNET_MESH_peer_request_connect_add (session->tunnel, &session->peer);
1319 GNUNET_SERVER_receive_done (client, GNUNET_YES);
1320 session->state = WAITING_FOR_BOBS_CONNECT;
1321 }
1322 else
1323 {
1324 struct ServiceSession * requesting_session;
1325 enum SessionState needed_state = REQUEST_FROM_SERVICE_RECEIVED;
1326
1327 session->role = BOB;
1328 session->mask = NULL;
1329 // copy over the elements
1330 session->used_element_count = element_count;
1331 for (i = 0; i < element_count; i++)
1332 session->vector[i] = ntohl (vector[i]);
1333 session->state = MESSAGE_FROM_RESPONDING_CLIENT_RECEIVED;
1334
1335 GNUNET_CONTAINER_DLL_insert (from_client_head, from_client_tail, session);
1336 GNUNET_SERVER_receive_done (client, GNUNET_YES);
1337 //check if service queue contains a matching request
1338 requesting_session = find_matching_session (from_service_tail,
1339 &session->key,
1340 session->element_count,
1341 &needed_state, NULL);
1342 if (NULL != requesting_session)
1343 {
1344 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));
1345 if (GNUNET_OK != compute_service_response (requesting_session, session))
1346 {
1347 GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, session);
1348 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
1349 &prepare_client_end_notification,
1350 session);
1351 }
1352 }
1353 else
1354 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));
1355 // no matching session exists yet, store the response
1356 // for later processing by handle_service_request()
1357 }
1358}
1359
1360
1361/**
1362 * Function called for inbound tunnels.
1363 *
1364 * @param cls closure
1365 * @param tunnel new handle to the tunnel
1366 * @param initiator peer that started the tunnel
1367 * @param atsi performance information for the tunnel
1368 * @return initial tunnel context for the tunnel
1369 * (can be NULL -- that's not an error)
1370 */
1371static void *
1372tunnel_incoming_handler (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
1373 const struct GNUNET_PeerIdentity *initiator,
1374 const struct GNUNET_ATS_Information *atsi)
1375{
1376
1377 struct ServiceSession * c = GNUNET_new (struct ServiceSession);
1378
1379 memcpy (&c->peer, initiator, sizeof (struct GNUNET_PeerIdentity));
1380 c->tunnel = tunnel;
1381 c->role = BOB;
1382 return c;
1383}
1384
1385
1386/**
1387 * Function called whenever an inbound tunnel is destroyed. Should clean up
1388 * any associated state.
1389 *
1390 * @param cls closure (set from GNUNET_MESH_connect)
1391 * @param tunnel connection to the other end (henceforth invalid)
1392 * @param tunnel_ctx place where local state associated
1393 * with the tunnel is stored (our 'struct TunnelState')
1394 */
1395static void
1396tunnel_destruction_handler (void *cls,
1397 const struct GNUNET_MESH_Tunnel *tunnel,
1398 void *tunnel_ctx)
1399{
1400 struct ServiceSession * service_session = tunnel_ctx;
1401 struct ServiceSession * client_session;
1402 struct ServiceSession * curr;
1403
1404 GNUNET_assert (service_session);
1405 if (!memcmp (&service_session->peer, &me, sizeof (struct GNUNET_PeerIdentity)))
1406 return;
1407 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Tunnel destroyed, terminating session with peer (%s)\n"), GNUNET_i2s (&service_session->peer));
1408 // remove the session, unless it has already been dequeued, but somehow still active
1409 // this could bug without the IF in case the queue is empty and the service session was the only one know to the service
1410 for (curr = from_service_head; NULL != curr; curr = curr->next)
1411 if (curr == service_session)
1412 {
1413 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, curr);
1414 break;
1415 }
1416 // there is a client waiting for this service session, terminate it, too!
1417 // i assume the tupel of key and element count is unique. if it was not the rest of the code would not work either.
1418 client_session = find_matching_session (from_client_tail,
1419 &service_session->key,
1420 service_session->element_count,
1421 NULL, NULL);
1422 free_session (service_session);
1423
1424 // the client has to check if it was waiting for a result
1425 // or if it was a responder, no point in adding more statefulness
1426 if (client_session && ( ! do_shutdown))
1427 {
1428 // remove the session, we just found it in the queue, so it must be there
1429 GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, client_session);
1430 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
1431 &prepare_client_end_notification,
1432 client_session);
1433 }
1434}
1435
1436
1437/**
1438 * Compute our scalar product, done by Alice
1439 *
1440 * @param session - the session associated with this computation
1441 * @param kp - (1) from the protocol definition:
1442 * $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)})$
1443 * @param kq - (2) from the protocol definition:
1444 * $E_A(a_{\pi'(i)}) \otimes E_A(- r_{\pi'(i)}) &= E_A(a_{\pi'(i)} - r_{\pi'(i)})$
1445 * @param s - S from the protocol definition:
1446 * $S := E_A(\sum (r_i + b_i)^2)$
1447 * @param stick - S' from the protocol definition:
1448 * $S' := E_A(\sum r_i^2)$
1449 * @return product as MPI, never NULL
1450 */
1451static gcry_mpi_t
1452compute_scalar_product (struct ServiceSession * session,
1453 gcry_mpi_t * kp, gcry_mpi_t * kq, gcry_mpi_t s, gcry_mpi_t stick)
1454{
1455 uint16_t count;
1456 gcry_mpi_t divider;
1457 gcry_mpi_t t;
1458 gcry_mpi_t u;
1459 gcry_mpi_t utick;
1460 gcry_mpi_t p;
1461 gcry_mpi_t ptick;
1462 gcry_mpi_t product;
1463 gcry_mpi_t tmp;
1464 unsigned int i;
1465
1466 count = session->used_element_count;
1467 tmp = gcry_mpi_new (KEYBITS);
1468 for (i = 0; i < count; i++)
1469 {
1470 decrypt_element (kp[i], kp[i], my_mu, my_lambda, my_n, my_nsquare);
1471 decrypt_element (kq[i], kq[i], my_mu, my_lambda, my_n, my_nsquare);
1472 }
1473
1474 // calculate t = E(sum(ai))
1475 t = compute_square_sum (session->a, count);
1476 encrypt_element (t, t, NULL, my_g, my_n, my_nsquare);
1477
1478 // calculate U
1479 u = gcry_mpi_new (0);
1480 tmp = compute_square_sum (kp, count);
1481 gcry_mpi_sub (u, u, tmp);
1482 encrypt_element (u, u, NULL, my_g, my_n, my_nsquare);
1483 gcry_mpi_release (tmp);
1484
1485 //calculate U'
1486 utick = gcry_mpi_new (0);
1487 tmp = compute_square_sum (kq, count);
1488 gcry_mpi_sub (utick, utick, tmp);
1489 encrypt_element (utick, utick, NULL, my_g, my_n, my_nsquare);
1490 gcry_mpi_release (tmp);
1491
1492 GNUNET_assert (p = gcry_mpi_new (0));
1493 GNUNET_assert (ptick = gcry_mpi_new (0));
1494
1495 // compute P
1496 gcry_mpi_add (p, s, t);
1497 //gcry_mpi_mulm (p, p, u, my_nsquare);
1498 gcry_mpi_add (p, p, u);
1499 decrypt_element (p, p, my_mu, my_lambda, my_n, my_nsquare);
1500
1501 // compute P'
1502 gcry_mpi_add (ptick, stick, t);
1503 //gcry_mpi_mulm (ptick, ptick, utick, my_nsquare);
1504 gcry_mpi_add (ptick, ptick, utick);
1505 decrypt_element (ptick, ptick, my_mu, my_lambda, my_n, my_nsquare);
1506
1507 gcry_mpi_release (t);
1508 gcry_mpi_release (u);
1509 gcry_mpi_release (utick);
1510
1511 // compute product
1512 GNUNET_assert (product = gcry_mpi_new (0));
1513 gcry_mpi_sub (product, p, ptick);
1514 gcry_mpi_release (p);
1515 gcry_mpi_release (ptick);
1516 divider = gcry_mpi_set_ui (NULL, 2);
1517 gcry_mpi_div (product, NULL, product, divider, 0);
1518
1519 gcry_mpi_release (divider);
1520 for (i = 0; i < count; i++)
1521 gcry_mpi_release (session->a[i]);
1522 GNUNET_free (session->a);
1523 session->a = NULL;
1524
1525 return product;
1526}
1527
1528
1529/**
1530 * prepare the response we will send to alice or bobs' clients.
1531 * in Bobs case the product will be NULL.
1532 *
1533 * @param session the session associated with our client.
1534 */
1535static void
1536prepare_client_response (void *cls,
1537 const struct GNUNET_SCHEDULER_TaskContext *tc)
1538{
1539 struct ServiceSession * session = cls;
1540 struct GNUNET_VECTORPRODUCT_client_response * msg;
1541 unsigned char * product_exported = NULL;
1542 size_t product_length = 0;
1543 uint16_t msg_length = 0;
1544 struct MessageObject * msg_obj;
1545
1546 GNUNET_assert (session);
1547
1548 if (session->product)
1549 {
1550 // get representation as string
1551 GNUNET_assert ( ! gcry_mpi_aprint (GCRYMPI_FMT_USG,
1552 &product_exported,
1553 &product_length,
1554 session->product));
1555 gcry_mpi_release (session->product);
1556 session->product = NULL;
1557 }
1558
1559 msg_length = sizeof (struct GNUNET_VECTORPRODUCT_client_response) +product_length;
1560 msg = GNUNET_malloc (msg_length);
1561 memcpy (&msg[1], product_exported, product_length);
1562 GNUNET_free_non_null (product_exported);
1563 msg->header.type = htons (GNUNET_MESSAGE_TYPE_VECTORPRODUCT_SERVICE_TO_CLIENT);
1564 msg->header.size = htons (msg_length);
1565 memcpy (&msg->key, &session->key, sizeof (struct GNUNET_HashCode));
1566 memcpy (&msg->peer, &session->peer, sizeof ( struct GNUNET_PeerIdentity));
1567 msg->product_length = htonl (product_length);
1568
1569 msg_obj = GNUNET_malloc (sizeof (struct MessageObject));
1570 msg_obj->msg = (struct GNUNET_MessageHeader *) msg;
1571 msg_obj->transmit_handle = NULL; // don't reset the transmit handle
1572
1573 //transmit this message to our client
1574 session->client_transmit_handle =
1575 GNUNET_SERVER_notify_transmit_ready (session->client,
1576 msg_length,
1577 GNUNET_TIME_UNIT_FOREVER_REL,
1578 &do_send_message,
1579 msg_obj);
1580 if ( ! session->client_transmit_handle)
1581 {
1582 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);
1583 session->client = NULL;
1584 // callback was not called!
1585 GNUNET_free (msg_obj);
1586 GNUNET_free (msg);
1587 }
1588 else
1589 // gracefully sent message, just terminate session structure
1590 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Sent result to client (%p), this session (%s) has ended!\n"), session->client, GNUNET_h2s (&session->key));
1591 free_session (session);
1592}
1593
1594
1595/**
1596 * Handle a request from another service to calculate a vectorproduct with us.
1597 *
1598 * @param cls closure (set from GNUNET_MESH_connect)
1599 * @param tunnel connection to the other end
1600 * @param tunnel_ctx place to store local state associated with the tunnel
1601 * @param sender who sent the message
1602 * @param message the actual message
1603 * @param atsi performance data for the connection
1604 * @return GNUNET_OK to keep the connection open,
1605 * GNUNET_SYSERR to close it (signal serious error)
1606 */
1607static int
1608handle_service_request (void *cls,
1609 struct GNUNET_MESH_Tunnel * tunnel,
1610 void **tunnel_ctx,
1611 const struct GNUNET_PeerIdentity * sender,
1612 const struct GNUNET_MessageHeader * message,
1613 const struct GNUNET_ATS_Information * atsi)
1614{
1615 struct ServiceSession * session;
1616 struct GNUNET_VECTORPRODUCT_service_request * msg = (struct GNUNET_VECTORPRODUCT_service_request *) message;
1617 uint16_t mask_length;
1618 uint16_t pk_length;
1619 uint16_t used_elements;
1620 uint16_t element_count;
1621 uint16_t msg_length;
1622 unsigned char * current;
1623 struct ServiceSession * responder_session;
1624 int32_t i = -1;
1625 enum SessionState needed_state;
1626
1627 GNUNET_assert (NULL != message);
1628 GNUNET_assert (NULL != sender);
1629 GNUNET_assert (NULL != tunnel_ctx);
1630 session = (struct ServiceSession *) * tunnel_ctx;
1631 // is this tunnel already in use?
1632 if ( (session->next) || (from_service_head == session))
1633 {
1634 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Got a service request over a tunnel that is already in use, ignoring!\n"));
1635 return GNUNET_SYSERR;
1636 }
1637 // Check if message was sent by me, which would be bad!
1638 if ( ! memcmp (sender, &me, sizeof (struct GNUNET_PeerIdentity)))
1639 {
1640 GNUNET_break (0);
1641 GNUNET_free (session);
1642 return GNUNET_SYSERR;
1643 }
1644 // this protocol can at best be 1:N, but never M:N!
1645 // Check if the sender is not the peer, I am connected to, which would be bad!
1646 if (memcmp (sender, &session->peer, sizeof (struct GNUNET_PeerIdentity)))
1647 {
1648 GNUNET_break (0);
1649 GNUNET_free (session);
1650 return GNUNET_SYSERR;
1651 }
1652
1653 //we need at least a peer and one message id to compare
1654 if (ntohs (msg->header.size) < sizeof (struct GNUNET_VECTORPRODUCT_service_request))
1655 {
1656 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Too short message received from peer!\n"));
1657 GNUNET_free (session);
1658 return GNUNET_SYSERR;
1659 }
1660 mask_length = ntohs (msg->mask_length);
1661 pk_length = ntohs (msg->pk_length);
1662 used_elements = ntohs (msg->used_element_count);
1663 element_count = ntohs (msg->element_count);
1664 msg_length = sizeof (struct GNUNET_VECTORPRODUCT_service_request)
1665 + mask_length + pk_length + used_elements * PAILLIER_ELEMENT_LENGTH;
1666
1667 //sanity check: is the message as long as the message_count fields suggests?
1668 if ((ntohs (msg->header.size) != msg_length) || (element_count < used_elements)
1669 || (used_elements == 0) || (mask_length != (element_count / 8 + (element_count % 8 ? 1 : 0)))
1670 )
1671 {
1672 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Invalid message received from peer, message count does not match message length!\n"));
1673 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)));
1674 GNUNET_free (session);
1675 return GNUNET_SYSERR;
1676 }
1677 if (find_matching_session (from_service_tail,
1678 &msg->key,
1679 element_count,
1680 NULL,
1681 sender))
1682 {
1683 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Got message with duplicate session key (`%s'), ignoring service request.\n"), (const char *) &(msg->key));
1684 GNUNET_free (session);
1685 return GNUNET_SYSERR;
1686 }
1687
1688 memcpy (&session->peer, sender, sizeof (struct GNUNET_PeerIdentity));
1689 session->state = REQUEST_FROM_SERVICE_RECEIVED;
1690 session->element_count = ntohs (msg->element_count);
1691 session->used_element_count = used_elements;
1692 session->tunnel = tunnel;
1693
1694 // session key
1695 memcpy (&session->key, &msg->key, sizeof (struct GNUNET_HashCode));
1696 current = (unsigned char *) &msg[1];
1697 //preserve the mask, we will need that later on
1698 session->mask = GNUNET_malloc (mask_length);
1699 memcpy (session->mask, current, mask_length);
1700 //the public key
1701 current += mask_length;
1702
1703 //convert the publickey to sexp
1704 if (gcry_sexp_new (&session->remote_pubkey, current, pk_length, 1))
1705 {
1706 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not translate remote public key to sexpression!\n"));
1707 GNUNET_free (session->mask);
1708 GNUNET_free (session);
1709 return GNUNET_SYSERR;
1710 }
1711
1712 current += pk_length;
1713
1714 //check if service queue contains a matching request
1715 needed_state = MESSAGE_FROM_RESPONDING_CLIENT_RECEIVED;
1716 responder_session = find_matching_session (from_client_tail,
1717 &session->key,
1718 session->element_count,
1719 &needed_state, NULL);
1720
1721 session->a = GNUNET_malloc (sizeof (gcry_mpi_t) * used_elements);
1722
1723 if (GNUNET_SERVER_MAX_MESSAGE_SIZE >= sizeof (struct GNUNET_VECTORPRODUCT_service_request)
1724 +pk_length
1725 + mask_length
1726 + used_elements * PAILLIER_ELEMENT_LENGTH)
1727 {
1728 gcry_error_t ret = 0;
1729 session->a = GNUNET_malloc (sizeof (gcry_mpi_t) * used_elements);
1730 // Convert each vector element to MPI_value
1731 for (i = 0; i < used_elements; i++)
1732 {
1733 size_t read = 0;
1734
1735 ret = gcry_mpi_scan (&session->a[i],
1736 GCRYMPI_FMT_USG,
1737 &current[i * PAILLIER_ELEMENT_LENGTH],
1738 PAILLIER_ELEMENT_LENGTH,
1739 &read);
1740 if (ret) // read < GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH
1741 {
1742 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not translate E[a%d] to MPI!\n%s/%s\n"),
1743 i, gcry_strsource (ret), gcry_strerror (ret));
1744 goto except;
1745 }
1746 }
1747 GNUNET_CONTAINER_DLL_insert (from_service_head, from_service_tail, session);
1748 if (responder_session)
1749 {
1750 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got session with key %s and a matching element set, processing.\n"), GNUNET_h2s (&session->key));
1751 if (GNUNET_OK != compute_service_response (session, responder_session))
1752 {
1753 //something went wrong, remove it again...
1754 GNUNET_CONTAINER_DLL_remove (from_service_head, from_service_tail, session);
1755 goto except;
1756 }
1757 }
1758 else
1759 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Got session with key %s without a matching element set, queueing.\n"), GNUNET_h2s (&session->key));
1760 return GNUNET_OK;
1761 }
1762 else
1763 {
1764 // TODO FEATURE: fallback to fragmentation, in case the message is too long
1765 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Message too large, fragmentation is currently not supported!\n"));
1766 goto except;
1767 }
1768except:
1769 for (i = 0; i < used_elements; i++)
1770 if (session->a[i])
1771 gcry_mpi_release (session->a[i]);
1772 gcry_sexp_release (session->remote_pubkey);
1773 session->remote_pubkey = NULL;
1774 GNUNET_free_non_null (session->a);
1775 session->a = NULL;
1776 free_session (session);
1777 // and notify our client-session that we could not complete the session
1778 if (responder_session)
1779 {
1780 // we just found the responder session in this queue
1781 GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, responder_session);
1782 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
1783 &prepare_client_end_notification,
1784 responder_session);
1785 }
1786 return GNUNET_SYSERR;
1787}
1788
1789
1790/**
1791 * Handle a response we got from another service we wanted to calculate a vectorproduct with.
1792 *
1793 * @param cls closure (set from GNUNET_MESH_connect)
1794 * @param tunnel connection to the other end
1795 * @param tunnel_ctx place to store local state associated with the tunnel
1796 * @param sender who sent the message
1797 * @param message the actual message
1798 * @param atsi performance data for the connection
1799 * @return GNUNET_OK to keep the connection open,
1800 * GNUNET_SYSERR to close it (signal serious error)
1801 */
1802static int
1803handle_service_response (void *cls,
1804 struct GNUNET_MESH_Tunnel * tunnel,
1805 void **tunnel_ctx,
1806 const struct GNUNET_PeerIdentity * sender,
1807 const struct GNUNET_MessageHeader * message,
1808 const struct GNUNET_ATS_Information * atsi)
1809{
1810
1811 struct ServiceSession * session;
1812 struct GNUNET_VECTORPRODUCT_service_response * msg = (struct GNUNET_VECTORPRODUCT_service_response *) message;
1813 unsigned char * current;
1814 uint16_t count;
1815 gcry_mpi_t s = NULL;
1816 gcry_mpi_t stick = NULL;
1817 size_t read;
1818 size_t i;
1819 uint16_t used_element_count;
1820 size_t msg_size;
1821 gcry_mpi_t * kp = NULL;
1822 gcry_mpi_t * kq = NULL;
1823
1824 GNUNET_assert (NULL != message);
1825 GNUNET_assert (NULL != sender);
1826 GNUNET_assert (NULL != tunnel_ctx);
1827 session = (struct ServiceSession *) * tunnel_ctx;
1828 GNUNET_assert (NULL != session);
1829 count = session->used_element_count;
1830 session->product = NULL;
1831
1832 if (memcmp (&session->peer, sender, sizeof (struct GNUNET_PeerIdentity)))
1833 {
1834 GNUNET_break_op (0);
1835 goto invalid_msg;
1836 }
1837 //we need at least a peer and one message id to compare
1838 if (sizeof (struct GNUNET_VECTORPRODUCT_service_response) > ntohs (msg->header.size))
1839 {
1840 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Too short message received from peer!\n"));
1841 goto invalid_msg;
1842 }
1843 used_element_count = ntohs (msg->used_element_count);
1844 msg_size = sizeof (struct GNUNET_VECTORPRODUCT_service_response)
1845 + 2 * used_element_count * PAILLIER_ELEMENT_LENGTH
1846 + 2 * PAILLIER_ELEMENT_LENGTH;
1847 //sanity check: is the message as long as the message_count fields suggests?
1848 if ((ntohs (msg->header.size) != msg_size) || (count != used_element_count))
1849 {
1850 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Invalid message received from peer!\n"));
1851 goto invalid_msg;
1852 }
1853 if (GNUNET_SERVER_MAX_MESSAGE_SIZE < msg_size)
1854 {
1855 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Message too large, fragmentation is currently not supported!\n"));
1856 goto invalid_msg;
1857 }
1858
1859 //convert s
1860 current = (unsigned char *) &msg[1];
1861 if (gcry_mpi_scan (&s, GCRYMPI_FMT_USG, current,
1862 PAILLIER_ELEMENT_LENGTH, &read))
1863 {
1864 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not translate s to an MPI value!\n"));
1865 goto invalid_msg;
1866 }
1867 current += PAILLIER_ELEMENT_LENGTH;
1868 //convert stick
1869 if (gcry_mpi_scan (&stick, GCRYMPI_FMT_USG, current,
1870 PAILLIER_ELEMENT_LENGTH, &read))
1871 {
1872 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not translate s' to an MPI value!\n"));
1873 goto invalid_msg;
1874 }
1875 current += PAILLIER_ELEMENT_LENGTH;
1876
1877 kp = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
1878 // Convert each kp[] to its MPI_value
1879 for (i = 0; i < count; i++)
1880 {
1881 if (gcry_mpi_scan (&kp[i], GCRYMPI_FMT_USG, current,
1882 PAILLIER_ELEMENT_LENGTH, &read))
1883 {
1884 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not translate Kp[%d]to an MPI value!\n"), i);
1885 goto invalid_msg;
1886 }
1887 current += PAILLIER_ELEMENT_LENGTH;
1888 }
1889
1890
1891 kq = GNUNET_malloc (sizeof (gcry_mpi_t) * count);
1892 // Convert each kq[] to its MPI_value
1893 for (i = 0; i < count; i++)
1894 {
1895 if (gcry_mpi_scan (&kq[i], GCRYMPI_FMT_USG, current,
1896 PAILLIER_ELEMENT_LENGTH, &read))
1897 {
1898 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not translate Kq[%d]to an MPI value!\n"), i);
1899 goto invalid_msg;
1900 }
1901 current += PAILLIER_ELEMENT_LENGTH;
1902 }
1903
1904 session->product = compute_scalar_product (session, kp, kq, s, stick);
1905
1906invalid_msg:
1907 if (s)
1908 gcry_mpi_release (s);
1909 if (stick)
1910 gcry_mpi_release (stick);
1911 for (i = 0; kp && i < count; i++)
1912 if (kp[i]) gcry_mpi_release (kp[i]);
1913 for (i = 0; kq && i < count; i++)
1914 if (kq[i]) gcry_mpi_release (kq[i]);
1915 GNUNET_free_non_null (kp);
1916 GNUNET_free_non_null (kq);
1917
1918 session->state = FINALIZED;
1919 // the tunnel has done its job, terminate our connection and the tunnel
1920 // the peer will be notified that the tunnel was destroyed via tunnel_destruction_handler
1921 GNUNET_CONTAINER_DLL_remove (from_client_head, from_client_tail, session);
1922 GNUNET_SCHEDULER_add_now (&destroy_tunnel, session);
1923 // send message with product to client
1924 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
1925 &prepare_client_response, session);
1926 return GNUNET_OK;
1927 // if success: terminate the session gracefully, else terminate with error
1928}
1929
1930
1931/**
1932 * Task run during shutdown.
1933 *
1934 * @param cls unused
1935 * @param tc unused
1936 */
1937static void
1938shutdown_task (void *cls,
1939 const struct GNUNET_SCHEDULER_TaskContext *tc)
1940{
1941 struct ServiceSession * curr;
1942 struct ServiceSession * next;
1943 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Shutting down, initiating cleanup.\n"));
1944
1945 do_shutdown = GNUNET_YES;
1946 // terminate all owned open tunnels.
1947 for (curr = from_client_head; NULL != curr; curr = next)
1948 {
1949 next = curr->next;
1950 if (FINALIZED != curr->state)
1951 {
1952 destroy_tunnel (curr, NULL);
1953 curr->state = FINALIZED;
1954 }
1955 }
1956
1957 if (my_core)
1958 {
1959 GNUNET_CORE_disconnect (my_core);
1960 my_core = NULL;
1961 }
1962
1963 if (my_mesh)
1964 {
1965 GNUNET_MESH_disconnect (my_mesh);
1966 my_mesh = NULL;
1967 }
1968}
1969
1970
1971/**
1972 * To be called on core init/fail.
1973 *
1974 * @param cls closure, NULL
1975 * @param server handle to the server for this service
1976 * @param my_identity the public identity of this peer
1977 */
1978static void
1979core_init (void *cls, struct GNUNET_CORE_Handle *server,
1980 const struct GNUNET_PeerIdentity *my_identity)
1981{
1982 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Core initialized\n"));
1983 me = *my_identity;
1984}
1985
1986
1987/**
1988 * Initialization of the program and message handlers
1989 *
1990 * @param cls closure
1991 * @param server the initialized server
1992 * @param c configuration to use
1993 */
1994static void
1995run (void *cls,
1996 struct GNUNET_SERVER_Handle *server,
1997 const struct GNUNET_CONFIGURATION_Handle *c)
1998{
1999 static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
2000 {&handle_client_request, NULL, GNUNET_MESSAGE_TYPE_VECTORPRODUCT_CLIENT_TO_ALICE, 0},
2001 {&handle_client_request, NULL, GNUNET_MESSAGE_TYPE_VECTORPRODUCT_CLIENT_TO_BOB, 0},
2002 {NULL, NULL, 0, 0}
2003 };
2004 static const struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
2005 { &handle_service_request, GNUNET_MESSAGE_TYPE_VECTORPRODUCT_ALICE_TO_BOB, 0},
2006 { &handle_service_response, GNUNET_MESSAGE_TYPE_VECTORPRODUCT_BOB_TO_ALICE, 0},
2007 {NULL, 0, 0}
2008 };
2009 static const struct GNUNET_CORE_MessageHandler core_handlers[] = {
2010 {NULL, 0, 0}
2011 };
2012 static GNUNET_MESH_ApplicationType mesh_types[] = {
2013 GNUNET_APPLICATION_TYPE_VECTORPRODUCT,
2014 GNUNET_APPLICATION_TYPE_END
2015 };
2016
2017 //generate private/public key set
2018 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Generating rsa-key.\n"));
2019 generate_keyset ();
2020 // register server callbacks and disconnect handler
2021 GNUNET_SERVER_add_handlers (server, server_handlers);
2022 GNUNET_SERVER_disconnect_notify (server,
2023 &handle_client_disconnect,
2024 NULL);
2025
2026 my_core = GNUNET_CORE_connect (c, NULL, &core_init, NULL, NULL, NULL,
2027 GNUNET_NO, NULL, GNUNET_NO, core_handlers);
2028 if (!my_core)
2029 {
2030 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Connect to CORE failed\n"));
2031 return;
2032 }
2033 my_mesh = GNUNET_MESH_connect (c, NULL,
2034 &tunnel_incoming_handler,
2035 &tunnel_destruction_handler,
2036 mesh_handlers, mesh_types);
2037 if (!my_mesh)
2038 {
2039 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Connect to MESH failed\n"));
2040 GNUNET_SCHEDULER_shutdown ();
2041 return;
2042 }
2043 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Mesh initialized\n"));
2044 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
2045 &shutdown_task,
2046 NULL);
2047}
2048
2049
2050/**
2051 * The main function for the vectorproduct service.
2052 *
2053 * @param argc number of arguments from the command line
2054 * @param argv command line arguments
2055 * @return 0 ok, 1 on error
2056 */
2057int
2058main (int argc, char *const *argv)
2059{
2060 return (GNUNET_OK ==
2061 GNUNET_SERVICE_run (argc, argv,
2062 "vectorproduct",
2063 GNUNET_SERVICE_OPTION_NONE,
2064 &run, NULL)) ? 0 : 1;
2065}
2066
2067/* end of gnunet-service-ext.c */
diff --git a/src/vectorproduct/gnunet-vectorproduct.c b/src/vectorproduct/gnunet-vectorproduct.c
new file mode 100644
index 000000000..449085593
--- /dev/null
+++ b/src/vectorproduct/gnunet-vectorproduct.c
@@ -0,0 +1,410 @@
1/*
2 This file is part of GNUnet.
3 (C) 2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
21/**
22 * @file vectorproduct/gnunet-vectorproduct.c
23 * @brief vectorproduct client
24 * @author Christian M. Fuchs
25 */
26#define GCRYPT_NO_DEPRECATED
27#include <gcrypt.h>
28#include <inttypes.h>
29
30#include "platform.h"
31#include "gnunet_util_lib.h"
32#include "gnunet_vectorproduct_service.h"
33#include "gnunet_protocols.h"
34
35#define LOG(kind,...) GNUNET_log_from (kind, "gnunet-vectorproduct",__VA_ARGS__)
36/**
37 * Option -p: destination peer identity for checking message-ids with
38 */
39static char *input_peer_id = NULL;
40
41/**
42 * Option -p: destination peer identity for checking message-ids with
43 */
44static char *input_key = NULL;
45
46/**
47 * Option -e: vector to calculate a vectorproduct with
48 */
49static char *input_elements = NULL;
50
51/**
52 * Option -m: message-ids to calculate a vectorproduct with
53 */
54static char *input_mask = NULL;
55
56/**
57 * the count of the messages sent to the service for processing
58 */
59static unsigned short element_count;
60
61/**
62 * the count of the mask bytes
63 */
64unsigned short mask_length = 0;
65
66/**
67 * the count of the number of mask bytes
68 */
69unsigned short mask_bytes;
70
71/**
72 * the array of converted message IDs to send to our service
73 */
74static int32_t * elements = NULL;
75
76/**
77 * the array of converted message IDs to send to our service
78 */
79static unsigned char * mask = NULL;
80
81/**
82 * information about the peer we are comparing with
83 */
84struct GNUNET_PeerIdentity peer;
85
86/**
87 * information about the peer we are comparing with
88 */
89struct GNUNET_HashCode key;
90
91/**
92 * Pointer to the GNUNET_VECTORPRODUCT_Handle
93 */
94struct GNUNET_VECTORPRODUCT_Handle *handle;
95
96/**
97 * Global return value
98 */
99static int ret;
100
101struct GNUNET_VECTORPRODUCT_TestCls
102{
103 struct GNUNET_VECTORPRODUCT_Handle * h;
104};
105
106struct GNUNET_VECTORPRODUCT_TestCls test_cls;
107
108
109/**
110 * Callback called if we are initiating a new computation session
111 *
112 * @param cls unused
113 * @param status if our job was successfully processed
114 */
115static void
116responder_callback (void *cls,
117 const struct GNUNET_HashCode * key,
118 enum GNUNET_VECTORPRODUCT_ResponseStatus status)
119{
120 ret = -1;
121
122 switch (status)
123 {
124 case GNUNET_VECTORPRODUCT_Status_Success:
125 ret = 0;
126 LOG (GNUNET_ERROR_TYPE_INFO, "Session %s concluded.\n", GNUNET_h2s (key));
127 break;
128 case GNUNET_VECTORPRODUCT_Status_InvalidResponse:
129 LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: invalid response\n", GNUNET_h2s (key));
130 break;
131 case GNUNET_VECTORPRODUCT_Status_Timeout:
132 LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: timeout\n", GNUNET_h2s (key));
133 break;
134 case GNUNET_VECTORPRODUCT_Status_Failure:
135 LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: service failure\n", GNUNET_h2s (key));
136 case GNUNET_VECTORPRODUCT_Status_ServiceDisconnected:
137 LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: service disconnect!!\n", GNUNET_h2s (key));
138 break;
139 default:
140 LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: return code %d\n", GNUNET_h2s (key), (int) status);
141 }
142
143 GNUNET_VECTORPRODUCT_disconnect (handle);
144 GNUNET_SCHEDULER_shutdown ();
145}
146
147
148/**
149 * Callback called if we are initiating a new computation session
150 *
151 * @param cls unused
152 * @param key unused
153 * @param peer unused
154 * @param status if our job was successfully processed
155 * @param size size of the msg returned
156 * @param msg the response we got.
157 * @param type of the message received
158 */
159static void
160requester_callback (void *cls,
161 const struct GNUNET_HashCode * key,
162 const struct GNUNET_PeerIdentity * peer,
163 enum GNUNET_VECTORPRODUCT_ResponseStatus status,
164 const struct GNUNET_VECTORPRODUCT_client_response *msg)
165{
166 uint32_t product_len;
167 ret = -1;
168
169 switch (status)
170 {
171 case GNUNET_VECTORPRODUCT_Status_Success:
172 product_len = ntohl (msg->product_length);
173
174 LOG (GNUNET_ERROR_TYPE_INFO, "Session %s concluded.\n", GNUNET_h2s (key));
175
176 if (0 < product_len && NULL != &msg[1])
177 {
178 gcry_mpi_t result;
179 size_t read = 0;
180
181 if (0 != gcry_mpi_scan (&result, GCRYMPI_FMT_USG, &msg[1], product_len, &read))
182 LOG (GNUNET_ERROR_TYPE_ERROR, "Could not convert to mpi to value!\n");
183 else
184 {
185 unsigned char * buf;
186 gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buf, NULL, result);
187
188 printf ("Successfully computed result for session %s: %s\n", GNUNET_h2s (key), buf);
189 ret = 0;
190 }
191 }
192 else
193 { //currently not used, but if we get more info due to MESH we will need this
194 LOG (GNUNET_ERROR_TYPE_ERROR, "Service-side error in session %s, return code: %d\n", GNUNET_h2s (key), product_len);
195 }
196 break;
197 case GNUNET_VECTORPRODUCT_Status_InvalidResponse:
198 LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: invalid response\n", GNUNET_h2s (key));
199 break;
200 case GNUNET_VECTORPRODUCT_Status_Timeout:
201 LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: timeout\n", GNUNET_h2s (key));
202 break;
203 case GNUNET_VECTORPRODUCT_Status_Failure:
204 LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: service failure\n", GNUNET_h2s (key));
205 case GNUNET_VECTORPRODUCT_Status_ServiceDisconnected:
206 LOG (GNUNET_ERROR_TYPE_ERROR, "Disconnected from service.\n", GNUNET_h2s (key));
207 break;
208 default:
209 LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: return code %d\n", GNUNET_h2s (key), (int) status);
210 }
211 GNUNET_VECTORPRODUCT_disconnect (handle);
212 GNUNET_SCHEDULER_shutdown ();
213}
214
215
216/**
217 * Main function that will be run by the scheduler.
218 *
219 * @param cls closure
220 * @param args remaining command-line arguments
221 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
222 * @param cfg configuration
223 */
224static void
225run (void *cls,
226 char *const *args,
227 const char *cfgfile,
228 const struct GNUNET_CONFIGURATION_Handle *cfg)
229{
230 char * begin = input_elements;
231 char * end;
232 int32_t element;
233 int i;
234 ret = -1;
235
236 if (NULL == input_elements)
237 {
238 FPRINTF (stderr, "%s", _ ("You must specify at least one message ID to check!\n"));
239 return;
240 }
241
242 if (NULL == input_key)
243 {
244 FPRINTF (stderr, "%s", _ ("This program needs a session identifier for comparing vectors.\n"));
245 return;
246 }
247
248 if (1 > strnlen (input_key, sizeof (struct GNUNET_HashCode)))
249 {
250 FPRINTF (stderr, _ ("Please give a session key for --input_key!\n"));
251 return;
252 }
253 GNUNET_CRYPTO_hash (input_key, strlen (input_key), &key);
254
255 if (input_peer_id && GNUNET_OK != GNUNET_CRYPTO_hash_from_string (input_peer_id,
256 (struct GNUNET_HashCode *) &peer))
257 {
258 FPRINTF (stderr, _ ("Tried to set initiator mode, as peer ID was given. "
259 "However, `%s' is not a valid peer identifier.\n"),
260 input_peer_id);
261 return;
262 }
263
264 int exit_loop = 0;
265 /* Read input_elements_peer1, and put in elements_peer1 array */
266 do
267 {
268 unsigned int mcount = element_count;
269 //ignore empty rows of ,,,,,,
270 while (*begin == ',')
271 begin++;
272 // get the length of the current element and replace , with null
273 for (end = begin; *end && *end != ','; end++);
274
275 if (*end == '\0')
276 exit_loop = 1;
277
278 if (*end == ',')
279 *end = '\0';
280
281 if (1 != sscanf (begin, "%" SCNd32, &element))
282 {
283 FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
284 return;
285 }
286
287 GNUNET_array_append (elements, mcount, element);
288 element_count++;
289
290 begin = ++end;
291 }
292 while (!exit_loop);
293
294 GNUNET_assert (elements != NULL);
295 GNUNET_assert (element_count > 1);
296 mask_length = element_count / 8 + (element_count % 8 ? 1 : 0);
297 mask = GNUNET_malloc ((element_count / 8) + 2);
298
299 /* Read input_mask_peer1 and read in mask_peer1 array */
300 if (NULL != input_mask)
301 {
302 begin = input_mask;
303 unsigned short mask_count = 0;
304 int exit_loop = 0;
305
306 do
307 {
308 //ignore empty rows of ,,,,,,
309 while (* begin == ',')
310 begin++;
311 // get the length of the current element and replace , with null
312 // gnunet_ascii-armor uses base32, thus we can use , as separator!
313 for (end = begin; *end && *end != ','; end++);
314
315 if (*end == '\0')
316 exit_loop = 1;
317
318 if (*end == ',')
319 *end = '\0';
320
321 if (1 != sscanf (begin, "%" SCNd32, &element))
322 {
323 FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
324 return;
325 }
326
327 GNUNET_assert (mask_count <= element_count);
328
329 if (element)
330 mask[mask_count / 8] = mask[mask_count / 8] | 1 << (mask_count % 8);
331
332 mask_count++;
333 begin = ++end;
334 }
335 while (!exit_loop);
336 // +1 to see if we would have more data, which would indicate malformed/superficial input
337 GNUNET_assert (mask_count == element_count);
338 }
339 else if (input_peer_id)
340 {
341 for (i = 0; i <= mask_length; i++)
342 mask[i] = UCHAR_MAX; // all 1's
343 }
344
345 handle = GNUNET_VECTORPRODUCT_connect (cfg);
346 if (handle == NULL)
347 {
348 FPRINTF (stderr, _ ("Could not connect to the GNUNET Vector Product Service\n"));
349 return;
350 }
351
352 test_cls.h = handle;
353
354 if (input_peer_id && !GNUNET_VECTORPRODUCT_request (handle,
355 &key,
356 &peer,
357 element_count,
358 mask_length,
359 elements, mask,
360 GNUNET_TIME_UNIT_MINUTES,
361 &requester_callback,
362 (void *) &test_cls))
363 return;
364 if ( !input_peer_id && !GNUNET_VECTORPRODUCT_prepare_response (handle,
365 &key,
366 element_count,
367 elements,
368 GNUNET_TIME_UNIT_MINUTES,
369 &responder_callback,
370 (void *) &test_cls))
371 return;
372
373 ret = 0;
374}
375
376
377/**
378 * The main function to the vectorproduct client.
379 *
380 * @param argc number of arguments from the command line
381 * @param argv command line arguments
382 * @return 0 ok, 1 on error
383 */
384int
385main (int argc, char *const *argv)
386{
387 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
388 {'e', "elements", "\"val1,val2,...,valn\"",
389 gettext_noop ("A comma separated list of elements to compare as vector with our remote peer."),
390 1, &GNUNET_GETOPT_set_string, &input_elements},
391 {'m', "mask", "\"0,1,...,maskn\"",
392 gettext_noop ("A comma separated mask to select which elements should actually be compared."),
393 1, &GNUNET_GETOPT_set_string, &input_mask},
394 {'p', "peer", "PEERID",
395 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."),
396 1, &GNUNET_GETOPT_set_string, &input_peer_id},
397 {'k', "key", "TRANSACTION_ID",
398 gettext_noop ("Transaction ID shared with peer."),
399 1, &GNUNET_GETOPT_set_string, &input_key},
400 GNUNET_GETOPT_OPTION_END
401 };
402
403 return (GNUNET_OK ==
404 GNUNET_PROGRAM_run (argc,
405 argv,
406 "gnunet-vectorproduct",
407 gettext_noop ("Calculate the Vectorproduct with a GNUnet peer."),
408 options, &run, NULL)) ? ret : 1;
409}
410
diff --git a/src/vectorproduct/gnunet_vectorproduct.h b/src/vectorproduct/gnunet_vectorproduct.h
new file mode 100644
index 000000000..4b116646b
--- /dev/null
+++ b/src/vectorproduct/gnunet_vectorproduct.h
@@ -0,0 +1,274 @@
1/*
2 This file is part of GNUnet.
3 (C) 2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
21/**
22 * @file include/gnunet_vectorproduct.h
23 * @brief API to the vectorproduct service
24 * @author Christian M. Fuchs
25 */
26
27#ifndef GNUNET_VECTORPRODUCT_H
28#define GNUNET_VECTORPRODUCT_H
29
30///////////////////////////////////////////////////////////////////////////////
31// Defines
32///////////////////////////////////////////////////////////////////////////////
33#define DISABLE_CRYPTO
34
35/**
36 * Length of the key used for encryption
37 */
38#define KEYBITS 2048
39
40/**
41 * When performing our crypto, we may add two encrypted values with each
42 * a maximal length of GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH.
43 * thus we can receive a slightly longer element (+1 byte)
44 */
45#define PAILLIER_ELEMENT_LENGTH (2*KEYBITS/8 +1)
46
47#ifdef __cplusplus
48extern "C"
49{
50#endif
51
52///////////////////////////////////////////////////////////////////////////////
53// Service Structure Definitions
54///////////////////////////////////////////////////////////////////////////////
55
56/**
57 * Message type passed from requesting service Alice to responding service Bob
58 * to initiate a request and make bob participate in our protocol
59 */
60struct GNUNET_VECTORPRODUCT_service_request {
61 /**
62 * GNUNET message header
63 */
64 struct GNUNET_MessageHeader header;
65
66 /**
67 * how many bytes the mask has
68 */
69 uint16_t mask_length GNUNET_PACKED;
70
71 /**
72 * the length of the publickey contained within this message
73 */
74 uint16_t pk_length GNUNET_PACKED;
75
76 /**
77 * the transaction/session key used to identify a session
78 */
79 struct GNUNET_HashCode key;
80
81 /**
82 * how many elements the vector in payload contains
83 */
84 uint16_t element_count GNUNET_PACKED;
85
86 /**
87 * how many elements are actually included after the mask was applied.
88 */
89 uint16_t used_element_count GNUNET_PACKED;
90
91 /**
92 * followed by mask | public_key | vector[used_element_count]
93 */
94};
95
96/**
97 * Message type passed from responding service Bob to responding service Alice
98 * to complete a request and allow Alice to compute the result
99 */
100struct GNUNET_VECTORPRODUCT_service_response {
101 /**
102 * GNUNET message header
103 */
104 struct GNUNET_MessageHeader header;
105
106 /**
107 * how many elements the vector in payload contains
108 */
109 uint16_t element_count GNUNET_PACKED;
110
111 /**
112 * how many elements are actually included after the mask was applied.
113 */
114 uint16_t used_element_count GNUNET_PACKED;
115
116 /**
117 * the transaction/session key used to identify a session
118 */
119 struct GNUNET_HashCode key;
120
121 /**
122 * followed by s | s' | kp[] | kq[]
123 */
124};
125
126///////////////////////////////////////////////////////////////////////////////
127// Service Structure Definitions
128///////////////////////////////////////////////////////////////////////////////
129
130/**
131 * state a session can be in
132 */
133enum SessionState
134{
135 WAITING_FOR_BOBS_CONNECT,
136 MESSAGE_FROM_RESPONDING_CLIENT_RECEIVED,
137 WAITING_FOR_RESPONSE_FROM_SERVICE,
138 REQUEST_FROM_SERVICE_RECEIVED,
139 FINALIZED
140};
141
142/**
143 * role a peer in a session can assume
144 */
145enum PeerRole
146{
147 ALICE,
148 BOB
149};
150/**
151 * A vectorproduct session which tracks:
152 *
153 * a request form the client to our final response.
154 * or
155 * a request from a service to us(service).
156 */
157struct ServiceSession
158{
159 /**
160 * the role this peer has
161 */
162 enum PeerRole role;
163
164 /**
165 * session information is kept in a DLL
166 */
167 struct ServiceSession *next;
168
169 /**
170 * session information is kept in a DLL
171 */
172 struct ServiceSession *prev;
173
174 /**
175 * (hopefully) unique transaction ID
176 */
177 struct GNUNET_HashCode key;
178
179 /**
180 * state of the session
181 */
182 enum SessionState state;
183
184 /**
185 * Alice or Bob's peerID
186 */
187 struct GNUNET_PeerIdentity peer;
188
189 /**
190 * the client this request is related to
191 */
192 struct GNUNET_SERVER_Client * client;
193
194 /**
195 * how many elements we were supplied with from the client
196 */
197 uint16_t element_count;
198
199 /**
200 * how many elements actually are used after applying the mask
201 */
202 uint16_t used_element_count;
203
204 /**
205 * how many bytes the mask is long.
206 * just for convenience so we don't have to re-re-re calculate it each time
207 */
208 uint16_t mask_length;
209
210 /**
211 * all the vector elements we received
212 */
213 int32_t * vector;
214
215 /**
216 * mask of which elements to check
217 */
218 unsigned char * mask;
219
220 /**
221 * Public key of the remote service, only used by bob
222 */
223 gcry_sexp_t remote_pubkey;
224
225 /**
226 * E(ai)(Bob) or ai(Alice) after applying the mask
227 */
228 gcry_mpi_t * a;
229
230 /**
231 * The computed scalar
232 */
233 gcry_mpi_t product;
234
235 /**
236 * My transmit handle for the current message to a alice/bob
237 */
238 struct GNUNET_MESH_TransmitHandle * service_transmit_handle;
239
240 /**
241 * My transmit handle for the current message to the client
242 */
243 struct GNUNET_SERVER_TransmitHandle * client_transmit_handle;
244
245 /**
246 * tunnel-handle associated with our mesh handle
247 */
248 struct GNUNET_MESH_Tunnel * tunnel;
249
250};
251
252/**
253 * We need to do a minimum of bookkeeping to maintain track of our transmit handles.
254 * each msg is associated with a session and handle. using this information we can determine which msg was sent.
255 */
256struct MessageObject
257{
258 /**
259 * The handle used to transmit with this request
260 */
261 void ** transmit_handle;
262
263 /**
264 * The message to send
265 */
266 struct GNUNET_MessageHeader * msg;
267};
268
269#ifdef __cplusplus
270}
271#endif
272
273#endif /* GNUNET_VECTORPRODUCT_H */
274
diff --git a/src/vectorproduct/test_vectorproduct_api.c b/src/vectorproduct/test_vectorproduct_api.c
new file mode 100644
index 000000000..802015694
--- /dev/null
+++ b/src/vectorproduct/test_vectorproduct_api.c
@@ -0,0 +1,865 @@
1/*
2 This file is part of GNUnet.
3 (C) 2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
21/**
22 * Aim of test_vectorproduct_api : This test creates two peers. Peer1 is the
23 * responder peer, Bob and Peer2 is the initiator peer, Alice. Both peers
24 * connect to VectorProduct Service, and use the API to issue requests to
25 * service. Test passes, when the expected scalar product is received from the
26 * service.
27 */
28
29/**
30 * @file vectorproduct/testbed_vectorproduct_api.c
31 * @brief VectorProduct API testing between 4 peers using testing API
32 * @author Gaurav Kukreja
33 * @author Christian Fuchs
34 */
35
36#include <string.h>
37
38#include <inttypes.h>
39#include "platform.h"
40#include "gnunet_util_lib.h"
41#include "gnunet_testbed_service.h"
42#include "gnunet_common.h"
43#include "gnunet_vectorproduct_service.h"
44#include "gnunet_protocols.h"
45
46#define NUM_PEERS 2
47
48#define LOG(kind,...) GNUNET_log_from (kind, "test-vectorproduct-api",__VA_ARGS__)
49
50/**
51 * Structure for holding peer's sockets and IO Handles
52 */
53struct PeerData
54{
55 /**
56 * Handle to testbed peer
57 */
58 struct GNUNET_TESTBED_Peer *peer;
59
60 /**
61 * The service connect operation to stream
62 */
63 struct GNUNET_TESTBED_Operation *op;
64
65 /**
66 * Our Peer id
67 */
68 struct GNUNET_PeerIdentity our_id;
69
70 /**
71 * Pointer to Vector Product Handle
72 */
73 struct GNUNET_VECTORPRODUCT_Handle *vh;
74};
75
76/**
77 * Different states in test setup
78 */
79enum SetupState
80{
81 /**
82 * Get the identity of peer 1
83 */
84 PEER1_GET_IDENTITY,
85
86 /**
87 * Get the identity of peer 2
88 */
89 PEER2_GET_IDENTITY,
90
91 /**
92 * Connect to stream service of peer 1
93 */
94 PEER1_VECTORPRODUCT_CONNECT,
95
96 /**
97 * Connect to stream service of peer 2
98 */
99 PEER2_VECTORPRODUCT_CONNECT
100
101};
102
103/******************************************************************************
104 *** Global Variables *****************************
105 ******************************************************************************/
106
107/**
108 * Maximum allowed message-ids we can check in one go (with one GNUNET_message)
109 */
110static unsigned int max_mids;
111
112/**
113 * Session Key used by both the test peers
114 */
115char input_key[103] = "helloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhe";
116
117/**
118 * Input elements for peer1
119 */
120char 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";
121//char input_elements_peer1[] = "11,11,11";
122
123/**
124 * Input Mask for peer 1
125 */
126char 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";
127//char input_mask_peer1[] = "1,1,1";
128
129/**
130 * the array of converted message IDs to send to our service
131 */
132static int32_t * elements_peer1 = NULL;
133
134/**
135 * Number of elements
136 */
137uint16_t element_count_peer1 = 0;
138
139/**
140 * Input elements for peer2
141 */
142char 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";
143//char input_elements_peer2[] = "11,11,11";
144
145/**
146 * Input Mask for peer 2
147 */
148char 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";
149//char input_mask_peer2[] = "1,1,1";
150
151/**
152 * the array of converted message IDs to send to our service
153 */
154static int32_t * elements_peer2 = NULL;
155
156/**
157 * the array of converted message IDs to send to our service
158 */
159static unsigned char * mask_peer2 = NULL;
160
161/**
162 * Number of elements
163 */
164uint16_t element_count_peer2 = 0;
165
166/**
167 * Data context for peer 1
168 */
169static struct PeerData peer1;
170
171/**
172 * Data context for peer 2
173 */
174static struct PeerData peer2;
175
176/**
177 * Various states during test setup
178 */
179static enum SetupState setup_state;
180
181/**
182 * Testbed operation handle
183 */
184static struct GNUNET_TESTBED_Operation *op;
185
186static int ok;
187
188static int responder_ok;
189
190static int requester_ok;
191
192static GNUNET_SCHEDULER_TaskIdentifier abort_task;
193/******************************************************************************
194 *** Static Functions *****************************
195 ******************************************************************************/
196
197static void
198do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
199
200
201/**
202 * Close sockets and stop testing deamons nicely
203 */
204static void
205do_close (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
206{
207
208 if (peer1.op != NULL)
209 do_shutdown (&peer1, NULL);
210
211 if (peer2.op != NULL)
212 do_shutdown (&peer2, NULL);
213
214 if (GNUNET_SCHEDULER_NO_TASK != abort_task)
215 GNUNET_SCHEDULER_cancel (abort_task);
216
217 GNUNET_SCHEDULER_shutdown (); /* For shutting down testbed */
218}
219
220/**
221 * Shutdown a peer
222 *
223 * @param cls pointer to "struct PeerData" of the peer to be disconnected
224 * @param tc Task Context
225 */
226static void
227do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
228{
229 static int shutdown;
230 shutdown++;
231 struct PeerData* peer = (struct PeerData*) cls;
232
233 if (peer == &peer1)
234 LOG (GNUNET_ERROR_TYPE_INFO, "Disconnecting Peer1\n\n");
235 else if (peer == &peer2)
236 LOG (GNUNET_ERROR_TYPE_INFO, "Disconnecting Peer2\n\n");
237
238 // peer->op contains handle to the TESTBED_connect_service operation
239 // calling operation done, leads to call to vectorproduct_da
240 if (peer->op != NULL)
241 {
242 GNUNET_TESTBED_operation_done (peer->op);
243 peer->op = NULL;
244 }
245
246 if (shutdown >= 2)
247 GNUNET_SCHEDULER_add_now (&do_close, NULL);
248}
249
250
251/**
252 * Something went wrong and timed out. Kill everything and set error flag
253 */
254static void
255do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
256{
257 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: ABORT due to Timeout\n");
258 ok = GNUNET_SYSERR;
259 abort_task = 0;
260 do_close (cls, tc);
261}
262
263
264/**
265 * Controller event callback
266 *
267 * @param cls NULL
268 * @param event the controller event
269 */
270static void
271controller_event_cb (void *cls,
272 const struct GNUNET_TESTBED_EventInformation *event)
273{
274 GNUNET_assert (event->type == GNUNET_TESTBED_ET_OPERATION_FINISHED);
275
276 switch (setup_state)
277 {
278 case PEER1_VECTORPRODUCT_CONNECT:
279 case PEER2_VECTORPRODUCT_CONNECT:
280 GNUNET_assert (NULL == event->details.operation_finished.emsg);
281 break;
282 default:
283 GNUNET_assert (0);
284 }
285}
286
287
288static void
289responder_callback (void *cls,
290 const struct GNUNET_HashCode * key,
291 enum GNUNET_VECTORPRODUCT_ResponseStatus status)
292{
293
294 if (status == GNUNET_VECTORPRODUCT_Status_Failure)
295 {
296 LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received status failure\n");
297 responder_ok = -1;
298 }
299 else if (status == GNUNET_VECTORPRODUCT_Status_InvalidResponse)
300 {
301 LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received status invalid response\n");
302 responder_ok = -1;
303 }
304 else if (GNUNET_VECTORPRODUCT_Status_Timeout == status)
305 {
306 LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received timeout occured\n");
307 responder_ok = -1;
308 }
309 else if (GNUNET_VECTORPRODUCT_Status_ServiceDisconnected == status)
310 {
311 LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received service disconnected!!\n");
312 responder_ok = -1;
313 }
314 else if (GNUNET_VECTORPRODUCT_Status_Success == status)
315 {
316 LOG (GNUNET_ERROR_TYPE_INFO, "Responder Client expected response received!\n");
317 responder_ok = 1;
318 }
319 else
320 {
321 LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client status = %d!\n", (int) status);
322 responder_ok = -1;
323 }
324 // TODO : Responder Session Complete. Shutdown Test Cleanly!!!
325 //do_shutdown(&peer1, NULL);
326 GNUNET_SCHEDULER_add_now (&do_shutdown, &peer1);
327 return;
328}
329
330
331static void
332requester_callback (void *cls,
333 const struct GNUNET_HashCode * key,
334 const struct GNUNET_PeerIdentity * peer,
335 enum GNUNET_VECTORPRODUCT_ResponseStatus status,
336 const struct GNUNET_VECTORPRODUCT_client_response *msg)
337{
338 uint32_t product_len;
339
340 if (status == GNUNET_VECTORPRODUCT_Status_Failure)
341 {
342 LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client received status failure\n");
343 requester_ok = -1;
344 }
345 else if (status == GNUNET_VECTORPRODUCT_Status_InvalidResponse)
346 {
347 LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client received status invalid response\n");
348 requester_ok = -1;
349 }
350 else if (GNUNET_VECTORPRODUCT_Status_Timeout == status)
351 {
352 LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client timeout occured\n");
353 requester_ok = -1;
354 }
355 else if (GNUNET_VECTORPRODUCT_Status_ServiceDisconnected == status)
356 {
357 LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client service disconnected!!\n");
358 requester_ok = -1;
359 }
360 else if (GNUNET_VECTORPRODUCT_Status_Success != status)
361 {
362 LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client Status = %d\n", (int) status);
363 requester_ok = -1;
364 }
365 else if (GNUNET_VECTORPRODUCT_Status_Success == status)
366 {
367 LOG (GNUNET_ERROR_TYPE_INFO, "Requester Client expected response received!\n");
368 product_len = ntohl(msg->product_length);
369
370 if (0 < product_len)
371 {
372 gcry_mpi_t result;
373 gcry_error_t ret = 0;
374 size_t read = 0;
375 ret = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, &msg[1], product_len, &read);
376
377 if (0 != ret)
378 {
379 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Could not convert to mpi to value!\n");
380 ok = -1;
381 }
382 else
383 {
384 uint16_t i = 0;
385
386 // calculate expected product
387 gcry_mpi_t expected_result;
388 gcry_mpi_t v1;
389 gcry_mpi_t v2;
390 gcry_mpi_t v1_v2_prod;
391
392 expected_result = gcry_mpi_new (0);
393
394 for (i = 0; i < element_count_peer1; i++)
395 {
396 uint32_t value;
397 v1_v2_prod = gcry_mpi_new (0);
398
399 // long to gcry_mpi_t
400 value = elements_peer1[i] >= 0 ? elements_peer1[i] : -elements_peer1[i];
401 if (elements_peer1[i] < 0)
402 {
403 v1 = gcry_mpi_new (0);
404 gcry_mpi_sub_ui (v1, v1, value);
405 }
406 else
407 v1 = gcry_mpi_set_ui (NULL, value);
408
409 // long to gcry_mpi_t
410 value = elements_peer2[i] >= 0 ? elements_peer2[i] : -elements_peer2[i];
411 if (elements_peer2[i] < 0)
412 {
413 v2 = gcry_mpi_new (0);
414 gcry_mpi_sub_ui (v2, v2, value);
415 }
416 else
417 v2 = gcry_mpi_set_ui (NULL, value);
418
419 gcry_mpi_mul (v1_v2_prod, v1, v2);
420 gcry_mpi_add (expected_result, expected_result, v1_v2_prod);
421
422 gcry_mpi_release (v1);
423 gcry_mpi_release (v2);
424 gcry_mpi_release (v1_v2_prod);
425
426 }
427
428 // compare the result
429 if (!gcry_mpi_cmp (expected_result, result))
430 {
431 LOG (GNUNET_ERROR_TYPE_INFO, "Scalar Product matches expected Result!!\n");
432 requester_ok = 1;
433 }
434 else
435 {
436 LOG (GNUNET_ERROR_TYPE_WARNING, "Scalar Product DOES NOT match expected Result!!\n");
437 requester_ok = -1;
438 }
439 gcry_mpi_release (result);
440 gcry_mpi_release (expected_result);
441 }
442 }
443 else
444 { //currently not used, but if we get more info due to MESH we will need this
445 LOG (GNUNET_ERROR_TYPE_WARNING, "Error during computation of vector product, return code: %d\n", product_len);
446 requester_ok = -1;
447 }
448 }
449
450 //do_shutdown(&peer2, NULL);
451 GNUNET_SCHEDULER_add_now (&do_shutdown, &peer2);
452 return;
453}
454
455/**
456 * Prepare the message to be sent by peer2 to its vectorproduct service, to
457 * initiate a request to peer1.
458 */
459static struct GNUNET_VECTORPRODUCT_QueueEntry *
460requester_request ()
461{
462 unsigned int i;
463 int exit_loop;
464 uint16_t mask_length = 0;
465 char * begin = input_elements_peer2;
466 char * end;
467 int32_t element;
468 struct GNUNET_VECTORPRODUCT_QueueEntry *qe;
469 struct GNUNET_HashCode key;
470
471 GNUNET_assert (peer2.vh != NULL);
472
473 GNUNET_CRYPTO_hash (input_key, strlen (input_key), &key);
474
475 /* Read input_elements_peer2, and put in elements_peer2 array */
476 exit_loop = 0;
477 do
478 {
479 unsigned int mcount = element_count_peer2;
480 //ignore empty rows of ,,,,,,
481 while (*begin == ',')
482 begin++;
483 // get the length of the current element and replace , with null
484 for (end = begin; *end && *end != ','; end++);
485
486 if (*end == '\0')
487 exit_loop = 1;
488
489 if (1 != sscanf (begin, "%" SCNd32, &element))
490 {
491 FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
492 ok = -1;
493 return NULL;
494 }
495
496 GNUNET_array_append (elements_peer2, mcount, element);
497 element_count_peer2++;
498
499 begin = ++end;
500 }
501 while (!exit_loop && element_count_peer2 < max_mids);
502 GNUNET_assert (elements_peer2 != NULL);
503 GNUNET_assert (element_count_peer2 >= 1);
504
505 /* Read input_mask_peer2 and read in mask_peer2 array */
506 mask_length = element_count_peer2 / 8 + (element_count_peer2 % 8 ? 1 : 0);
507 mask_peer2 = GNUNET_malloc ((element_count_peer2 / 8) + 2);
508 GNUNET_assert (NULL != mask_peer2);
509 if (NULL != input_mask_peer2)
510 {
511 begin = input_mask_peer2;
512 unsigned short mask_count = 0;
513 int exit_loop = 0;
514
515 do
516 {
517 //ignore empty rows of ,,,,,,
518 while (* begin == ',')
519 begin++;
520 // get the length of the current element and replace , with null
521 // gnunet_ascii-armor uses base32, thus we can use , as separator!
522 for (end = begin; *end && *end != ','; end++);
523
524 if (*end == '\0')
525 exit_loop = 1;
526
527 if (1 != sscanf (begin, "%" SCNd32, &element))
528 {
529 FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
530 ok = -1;
531 return NULL;
532 }
533
534 GNUNET_assert (mask_count <= element_count_peer2);
535
536 if (element)
537 mask_peer2[mask_count / 8] = mask_peer2[mask_count / 8] | 1 << (mask_count % 8);
538
539 mask_count++;
540 begin = ++end;
541 }
542 while (!exit_loop);
543 // +1 to see if we would have more data, which would indicate malformed/superficial input
544 GNUNET_assert (mask_count == element_count_peer2);
545 }
546 else
547 {
548 for (i = 0; i <= mask_length; i++)
549 mask_peer2[i] = UCHAR_MAX; // all 1's
550 }
551
552 qe = GNUNET_VECTORPRODUCT_request (peer2.vh,
553 &key,
554 &peer1.our_id,
555 element_count_peer2,
556 mask_length,
557 elements_peer2, mask_peer2,
558 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
559 &requester_callback,
560 NULL);
561
562 if (qe == NULL)
563 {
564 LOG(GNUNET_ERROR_TYPE_ERROR, "Could not send request to vectorproduct service! Exitting!");
565 ok = -1;
566 return NULL;
567 }
568
569 return qe;
570}
571
572
573/**
574 * Function prepares the message to be sent by peer1 to its vectorproduct service
575 * to prepare response, and wait for a request session to be initiated by peer1
576 */
577static struct GNUNET_VECTORPRODUCT_QueueEntry *
578responder_prepare_response ()
579{
580 GNUNET_assert (peer1.vh != NULL);
581
582 char * begin = input_elements_peer1;
583 char * end;
584 int32_t element;
585 struct GNUNET_VECTORPRODUCT_QueueEntry *qe;
586 struct GNUNET_HashCode key;
587
588 GNUNET_CRYPTO_hash (input_key, strlen (input_key), &key);
589
590 /* Read input_elements_peer1, and put in elements_peer1 array */
591 int exit_loop = 0;
592 do
593 {
594 unsigned int mcount = element_count_peer1;
595 //ignore empty rows of ,,,,,,
596 while (*begin == ',')
597 begin++;
598 // get the length of the current element and replace , with null
599 for (end = begin; *end && *end != ','; end++);
600
601 if (*end == '\0')
602 exit_loop = 1;
603
604 if (1 != sscanf (begin, "%" SCNd32, &element))
605 {
606 FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
607 ok = -1;
608 return NULL;
609 }
610
611 GNUNET_array_append (elements_peer1, mcount, element);
612 element_count_peer1++;
613
614 begin = ++end;
615 }
616 while (!exit_loop && element_count_peer1 < max_mids);
617 GNUNET_assert (elements_peer1 != NULL);
618 GNUNET_assert (element_count_peer1 >= 1);
619
620 qe = GNUNET_VECTORPRODUCT_prepare_response (peer1.vh,
621 &key,
622 element_count_peer1,
623 elements_peer1,
624 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
625 &responder_callback,
626 NULL);
627
628 if (qe == NULL)
629 {
630 LOG(GNUNET_ERROR_TYPE_ERROR, "Could not send request to vectorproduct service! Exitting!");
631 ok = -1;
632 return NULL;
633 }
634
635 return qe;
636}
637
638
639/**
640 * Scheduler task to initiate requester client
641 *
642 * @param cls void* to struct PeerData
643 * @param tc Task Context
644 */
645static void
646request_task(void *cls,
647 const struct GNUNET_SCHEDULER_TaskContext
648 * tc)
649{
650 requester_request();
651 return;
652}
653
654/**
655 * Scheduler task to initiate responder client
656 *
657 * @param cls void* to struct PeerData
658 * @param tc Task Context
659 */
660static void
661prepare_response_task(void *cls,
662 const struct GNUNET_SCHEDULER_TaskContext
663 * tc)
664{
665 responder_prepare_response();
666 return;
667}
668
669
670/**
671 * Adapter function called to destroy a connection to
672 * a service. This function is called when GNUNET_TESTBED_operation_done is
673 * called for peer->op, which holds the handle for GNUNET_TESTBED_service_connect
674 * operation.
675 *
676 * @param cls closure
677 * @param op_result service handle returned from the connect adapter
678 */
679static void
680vectorproduct_da (void *cls, void *op_result)
681{
682 struct PeerData* peer = (struct PeerData*) cls;
683
684 GNUNET_VECTORPRODUCT_disconnect (peer->vh);
685 return;
686}
687
688
689/**
690 * Adapter function called to establish a connection to
691 * a service. This function is called to by GNUNET_TESTBED_service_connect.
692 *
693 * @param cls closure
694 * @param cfg configuration of the peer to connect to; will be available until
695 * GNUNET_TESTBED_operation_done() is called on the operation returned
696 * from GNUNET_TESTBED_service_connect()
697 * @return service handle to return in 'op_result', NULL on error
698 */
699static void *
700vectorproduct_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
701{
702 struct PeerData *p = cls;
703
704 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", (&peer1 == p) ? 1 : 2,
705 GNUNET_i2s (&p->our_id));
706
707 switch (setup_state)
708 {
709 case PEER1_VECTORPRODUCT_CONNECT:
710 /* Connect peer 2 to vectorproduct service */
711 {
712 peer2.op = GNUNET_TESTBED_service_connect (&peer2, peer2.peer, "vectorproduct",
713 NULL, NULL, vectorproduct_ca,
714 vectorproduct_da, &peer2);
715 setup_state = PEER2_VECTORPRODUCT_CONNECT;
716 }
717
718 /* Actually connect peer 1 to vectorproduct service */
719 peer1.vh = GNUNET_VECTORPRODUCT_connect (cfg);
720 return peer1.vh;
721
722 case PEER2_VECTORPRODUCT_CONNECT:
723 /* Actually connect peer 2 to vectorproduct service */
724 peer2.vh = GNUNET_VECTORPRODUCT_connect (cfg);
725
726 /* Schedule tasks to initiate request from peer2 and prepare_response from peer1 */
727 if(peer1.vh != NULL && peer2.vh != NULL)
728 {
729 GNUNET_SCHEDULER_add_now(&prepare_response_task, &peer1);
730 GNUNET_SCHEDULER_add_now(&request_task, &peer2);
731 }
732
733 return peer2.vh;
734 default:
735 GNUNET_assert (0);
736 }
737}
738
739
740/**
741 * Callback to be called when the requested peer information is available
742 *
743 * @param cb_cls the closure from GNUNET_TETSBED_peer_get_information()
744 * @param op the operation this callback corresponds to
745 * @param pinfo the result; will be NULL if the operation has failed
746 * @param emsg error message if the operation has failed; will be NULL if the
747 * operation is successfull
748 */
749static void
750peerinfo_cb (void *cb_cls, struct GNUNET_TESTBED_Operation *op_,
751 const struct GNUNET_TESTBED_PeerInformation *pinfo,
752 const char *emsg)
753{
754 GNUNET_assert (NULL == emsg);
755 GNUNET_assert (op == op_);
756 switch (setup_state)
757 {
758 case PEER1_GET_IDENTITY:
759 {
760 memcpy (&peer1.our_id, pinfo->result.id,
761 sizeof (struct GNUNET_PeerIdentity));
762 GNUNET_TESTBED_operation_done (op);
763
764 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 1 id: %s\n", GNUNET_i2s_full
765 (&peer1.our_id));
766
767 /* Request for peer id of peer 2*/
768 op = GNUNET_TESTBED_peer_get_information (peer2.peer,
769 GNUNET_TESTBED_PIT_IDENTITY,
770 &peerinfo_cb, NULL);
771 setup_state = PEER2_GET_IDENTITY;
772 }
773 break;
774 case PEER2_GET_IDENTITY:
775 {
776 memcpy (&peer2.our_id, pinfo->result.id,
777 sizeof (struct GNUNET_PeerIdentity));
778 GNUNET_TESTBED_operation_done (op);
779
780 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 2 id: %s\n", GNUNET_i2s_full
781 (&peer2.our_id));
782
783 /* Connect peer 1 to vectorproduct service */
784 peer1.op = GNUNET_TESTBED_service_connect (&peer1, peer1.peer, "vectorproduct",
785 NULL, NULL, vectorproduct_ca,
786 vectorproduct_da, &peer1);
787 setup_state = PEER1_VECTORPRODUCT_CONNECT;
788 }
789 break;
790 default:
791 GNUNET_assert (0);
792 }
793}
794
795
796/**
797 * Signature of a main function for a testcase.
798 *
799 * @param cls closure
800 * @param num_peers number of peers in 'peers'
801 * @param peers handle to peers run in the testbed
802 */
803static void
804test_master (void *cls, unsigned int num_peers,
805 struct GNUNET_TESTBED_Peer **peers)
806{
807 GNUNET_assert (NULL != peers);
808 GNUNET_assert (NULL != peers[0]);
809 GNUNET_assert (NULL != peers[1]);
810 peer1.peer = peers[0];
811 peer2.peer = peers[1];
812 /* Get the peer identity and configuration of peer 1 */
813 op = GNUNET_TESTBED_peer_get_information (peer1.peer,
814 GNUNET_TESTBED_PIT_IDENTITY,
815 &peerinfo_cb, NULL);
816 setup_state = PEER1_GET_IDENTITY;
817
818 /* Abort task for stopping test on timeout */
819 abort_task =
820 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
821 (GNUNET_TIME_UNIT_SECONDS, 20), &do_abort,
822 NULL);
823}
824
825
826/**
827 * Main function
828 */
829int
830main (int argc, char **argv)
831{
832 uint64_t event_mask;
833
834 ok = GNUNET_NO;
835 event_mask = 0;
836 event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
837 max_mids = (GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_MessageHeader))
838 / sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1;
839
840 (void) GNUNET_TESTBED_test_run ("test_vectorproduct_api",
841 "test_vectorproduct_api_data.conf",
842 NUM_PEERS, event_mask, &controller_event_cb,
843 NULL,
844 &test_master, NULL);
845
846 if (GNUNET_SYSERR == ok)
847 {
848 LOG (GNUNET_ERROR_TYPE_ERROR, "Test failing due to some error before calling API for request or prepare_response\n");
849 return 1;
850 }
851 else if (GNUNET_SYSERR == responder_ok)
852 {
853 LOG (GNUNET_ERROR_TYPE_ERROR, "Test failing due to some error in responding_client\n");
854 return 1;
855 }
856 else if (GNUNET_SYSERR == requester_ok)
857 {
858 LOG (GNUNET_ERROR_TYPE_ERROR, "Test failing due to some error in requesting client\n");
859 return 1;
860 }
861 else
862 return 0;
863}
864
865
diff --git a/src/vectorproduct/test_vectorproduct_api_4peers.c b/src/vectorproduct/test_vectorproduct_api_4peers.c
new file mode 100644
index 000000000..73ab634f9
--- /dev/null
+++ b/src/vectorproduct/test_vectorproduct_api_4peers.c
@@ -0,0 +1,1084 @@
1
2/*
3 This file is part of GNUnet.
4 (C) 2013 Christian Grothoff (and other contributing authors)
5
6 GNUnet is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; either version 3, or (at your
9 option) any later version.
10
11 GNUnet is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNUnet; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
20 */
21
22/**
23 * AIM OF THIS TEST
24 *
25 * The aim for the extended test is to verify the queuing functionality in the
26 * service and the API. The API queues requests received from the clients. The
27 * service queues requests that are received from other services.
28 *
29 * To test this, we create 4 peers. peer1 and peer2 are designated responders,
30 * and peer3 and peer4 are designated as requesters. Each peer calls API for the
31 * vectorproduct service accordingly.
32 *
33 * * peer1 tells the service to prepare response for requests with keys
34 * input_key_p1_p3(shared key b/w peer1 and peer3) and input_key_p1_p4.
35 * Similarly peer2 tells service to prepare response for requests with keys
36 * input_key_p2_p3, and input_key_p2_p4.
37 * * Simultaneously, peer3 tells its service to send a request to peer1 with key
38 * input_key_p1_p3, and a request to peer2 with key input_key_p2_p3. Similarly,
39 * peer 4 sends requests with appropriate keys.
40 *
41 * Each peer sends 2 requests to its service, which tests the queuing in API.
42 * Each service receives 2 requests from other service, which tests the queuing
43 * functionality in the service.
44 */
45
46
47/**
48 * @file vectorproduct/test_vectorproduct_api_4peers.c
49 * @brief Vectorproduct API testing between 4 peers using testing API
50 * @author Gaurav Kukreja
51 * @author Christian Fuchs
52 */
53
54#include <string.h>
55
56#include <inttypes.h>
57#include "platform.h"
58#include "gnunet_util_lib.h"
59#include "gnunet_testbed_service.h"
60#include "gnunet_common.h"
61#include "gnunet_vectorproduct_service.h"
62#include "gnunet_protocols.h"
63
64#define LOG(kind,...) GNUNET_log_from (kind, "test-vectorproduct-api-4peers",__VA_ARGS__)
65
66#define NUM_PEERS 4
67
68/**
69 * Structure for holding peer's sockets and IO Handles
70 */
71struct PeerData
72{
73 /**
74 * Handle to testbed peer
75 */
76 struct GNUNET_TESTBED_Peer *peer;
77
78 /**
79 * The service connect operation to stream
80 */
81 struct GNUNET_TESTBED_Operation *op;
82
83 /**
84 * Our Peer id
85 */
86 struct GNUNET_PeerIdentity our_id;
87
88 /**
89 * Pointer to Vector Product Handle
90 */
91 struct GNUNET_VECTORPRODUCT_Handle *vh;
92
93 /**
94 * Input elements for peer
95 */
96 char * input_elements;
97
98 /**
99 * Input Mask for peer
100 */
101 char * input_mask;
102
103 /**
104 * 2 Input keys for peer for 2 sessions of each peer
105 */
106 char * input_keys[2];
107
108 /**
109 * Number of requests(or prepare_response) sent by the peer
110 */
111 int request_num;
112
113 /**
114 * Number of callbacks received by the peer
115 */
116 int callback_num;
117
118 /**
119 * PeerData of the peers, this peer will talk to
120 */
121 struct PeerData * peers[2];
122
123
124};
125
126/**
127 * Different states in test setup
128 */
129enum SetupState
130{
131 /**
132 * Get the identity of peer 1
133 */
134 PEER1_GET_IDENTITY,
135
136 /**
137 * Get the identity of peer 2
138 */
139 PEER2_GET_IDENTITY,
140
141 /**
142 * Get the identity of peer 3
143 */
144 PEER3_GET_IDENTITY,
145
146 /**
147 * Get the identity of peer 4
148 */
149 PEER4_GET_IDENTITY,
150
151 /**
152 * Connect to stream service of peer 1
153 */
154 PEER1_VECTORPRODUCT_CONNECT,
155
156 /**
157 * Connect to stream service of peer 2
158 */
159 PEER2_VECTORPRODUCT_CONNECT,
160
161 /**
162 * Connect to stream service of peer 3
163 */
164 PEER3_VECTORPRODUCT_CONNECT,
165
166 /**
167 * Connect to stream service of peer 4
168 */
169 PEER4_VECTORPRODUCT_CONNECT
170
171};
172
173/******************************************************************************
174 *** Global Variables *****************************
175 ******************************************************************************/
176
177/**
178 * Maximum allowed message-ids we can check in one go (with one GNUNET_message)
179 */
180static unsigned int max_mids;
181
182/**
183 * Session Key used by both the test peers
184 */
185char input_key_p1_p3[103] = "111111111111111111111111111111111111111111111111113333333333333333333333333333333333333333333333333333";
186
187/**
188 * Session Key used by both the test peers
189 */
190char input_key_p1_p4[103] = "111111111111111111111111111111111111111111111111114444444444444444444444444444444444444444444444444444";
191
192/**
193 * Session Key used by both the test peers
194 */
195char input_key_p2_p3[103] = "222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333";
196
197/**
198 * Session Key used by both the test peers
199 */
200char input_key_p2_p4[103] = "222222222222222222222222222222222222222222222222224444444444444444444444444444444444444444444444444444";
201
202/**
203 * Input elements for peer1
204 */
205//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";
206char input_elements_peer1[] = "11,11,11";
207
208/**
209 * Input Mask for peer 1
210 */
211//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";
212char input_mask_peer1[] = "1,1,1";
213
214/**
215 * Input elements for peer2
216 */
217//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";
218char input_elements_peer2[] = "11,11,11";
219/**
220 * Input Mask for peer 2
221 */
222//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";
223char input_mask_peer2[] = "1,1,1";
224
225/**
226 * Input elements for peer3
227 */
228//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";
229char input_elements_peer3[] = "11,11,11";
230
231/**
232 * Input Mask for peer 3
233 */
234//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";
235char input_mask_peer3[] = "1,1,1";
236
237/**
238 * Input elements for peer4
239 */
240//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";
241char input_elements_peer4[] = "11,11,11";
242/**
243 * Input Mask for peer 4
244 */
245//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";
246char input_mask_peer4[] = "1,1,1";
247
248
249/**
250 * Data context for peer 1
251 */
252static struct PeerData peer1;
253
254/**
255 * Data context for peer 2
256 */
257static struct PeerData peer2;
258
259/**
260 * Data context for peer 3
261 */
262static struct PeerData peer3;
263
264/**
265 * Data context for peer 4
266 */
267static struct PeerData peer4;
268
269/**
270 * Various states during test setup
271 */
272static enum SetupState setup_state;
273
274/**
275 * Testbed operation handle
276 */
277static struct GNUNET_TESTBED_Operation *op;
278
279/**
280 * Return value for the test
281 */
282static int ok;
283
284/**
285 * Abort Task for timeout
286 */
287static GNUNET_SCHEDULER_TaskIdentifier abort_task;
288/******************************************************************************
289 *** Static Functions *****************************
290 ******************************************************************************/
291
292static void
293do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
294
295
296/**
297 * Close sockets and stop testing deamons nicely
298 */
299static void
300do_close (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
301{
302 if (peer1.op != NULL)
303 GNUNET_SCHEDULER_add_now (&do_shutdown, &peer1);
304
305 if (peer2.op != NULL)
306 GNUNET_SCHEDULER_add_now (&do_shutdown, &peer2);
307
308 if (peer3.op != NULL)
309 GNUNET_SCHEDULER_add_now (&do_shutdown, &peer3);
310
311 if (peer4.op != NULL)
312 GNUNET_SCHEDULER_add_now (&do_shutdown, &peer4);
313
314 if (GNUNET_SCHEDULER_NO_TASK != abort_task)
315 GNUNET_SCHEDULER_cancel (abort_task);
316
317 GNUNET_SCHEDULER_shutdown (); /* For shutting down testbed */
318}
319
320
321static void
322do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
323{
324 static int shutdown;
325 shutdown++;
326 struct PeerData* peer = (struct PeerData*) cls;
327
328 if (peer == &peer1)
329 LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down Peer 1!!! \n");
330 else if (peer == &peer2)
331 LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down Peer 2!!! \n");
332 else if (peer == &peer3)
333 LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down Peer 3!!! \n");
334 else if (peer == &peer4)
335 LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down Peer 4!!! \n");
336
337 // peer->op contains handle to the TESTBED_connect_service operation
338 // calling operation done, leads to call to vectorproduct_da
339 GNUNET_TESTBED_operation_done (peer->op);
340 peer->op = NULL;
341
342 if (shutdown == 4)
343 GNUNET_SCHEDULER_add_now (&do_close, NULL);
344}
345
346
347/**
348 * Something went wrong and timed out. Kill everything and set error flag
349 */
350static void
351do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
352{
353 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: ABORT due to Timeout\n");
354 ok = GNUNET_SYSERR;
355 abort_task = 0;
356 do_close (cls, tc);
357}
358
359
360/**
361 * Controller event callback
362 *
363 * @param cls NULL
364 * @param event the controller event
365 */
366static void
367controller_event_cb (void *cls,
368 const struct GNUNET_TESTBED_EventInformation *event)
369{
370 switch (event->type)
371 {
372 case GNUNET_TESTBED_ET_OPERATION_FINISHED:
373 switch (setup_state)
374 {
375 case PEER1_VECTORPRODUCT_CONNECT:
376 case PEER2_VECTORPRODUCT_CONNECT:
377 GNUNET_assert (NULL == event->details.operation_finished.emsg);
378 break;
379 default:
380 GNUNET_assert (0);
381 }
382 break;
383 default:
384 GNUNET_assert (0);
385 }
386}
387
388
389static void
390responder_callback (void *cls,
391 const struct GNUNET_HashCode * key,
392 enum GNUNET_VECTORPRODUCT_ResponseStatus status)
393{
394 struct PeerData * peer = cls;
395
396 peer->callback_num++;
397
398 if (peer == &peer1)
399 {
400 LOG (GNUNET_ERROR_TYPE_DEBUG, "Peer1 received callback!!!\n");
401 }
402 else if (peer == &peer2)
403 {
404 LOG (GNUNET_ERROR_TYPE_DEBUG, "Peer2 received callback!!!\n");
405 }
406 else
407 LOG (GNUNET_ERROR_TYPE_ERROR, "Requester callback received, but peer is neither peer1 nor peer2!!!\n");
408
409
410 if (status == GNUNET_VECTORPRODUCT_Status_Failure)
411 {
412 LOG (GNUNET_ERROR_TYPE_ERROR, "Responder Client received status failure\n");
413 ok = -1;
414 }
415 else if (status == GNUNET_VECTORPRODUCT_Status_InvalidResponse)
416 {
417 LOG (GNUNET_ERROR_TYPE_ERROR, "Responder Client received status invalid response\n");
418 ok = -1;
419 }
420 else if (GNUNET_VECTORPRODUCT_Status_Timeout == status)
421 {
422 LOG (GNUNET_ERROR_TYPE_ERROR, "Responder Client received timeout occured\n");
423 ok = -1;
424 }
425 else if (GNUNET_VECTORPRODUCT_Status_ServiceDisconnected == status)
426 {
427 LOG (GNUNET_ERROR_TYPE_ERROR, "Responder Client received service disconnected!!\n");
428 ok = -1;
429 }
430 else if (GNUNET_VECTORPRODUCT_Status_Success == status)
431 {
432 LOG (GNUNET_ERROR_TYPE_DEBUG, "Responder Client expected response received!\n");
433 ok = 1;
434 }
435 else
436 {
437 LOG (GNUNET_ERROR_TYPE_ERROR, "Responder Client status = %d!\n", (int) status);
438 ok = -1;
439 }
440
441 // TODO : Responder Session Complete. Shutdown Test Cleanly!!!
442 if (peer->callback_num == 2)
443 GNUNET_SCHEDULER_add_now (&do_shutdown, peer);
444}
445
446
447static void
448requester_callback (void *cls,
449 const struct GNUNET_HashCode * key,
450 const struct GNUNET_PeerIdentity * peer,
451 enum GNUNET_VECTORPRODUCT_ResponseStatus status,
452 const struct GNUNET_VECTORPRODUCT_client_response *msg)
453{
454 struct PeerData * peer_ = cls;
455 uint32_t product_len;
456
457 peer_->callback_num++;
458
459 if (peer_ == &peer3)
460 {
461 LOG (GNUNET_ERROR_TYPE_DEBUG, "Peer3 received callback!!!\n");
462 }
463 else if (peer_ == &peer4)
464 {
465 LOG (GNUNET_ERROR_TYPE_DEBUG, "Peer4 received callback!!!\n");
466 }
467 else
468 LOG (GNUNET_ERROR_TYPE_ERROR, "Requester callback received, but peer is neither peer3 nor peer4!!!\n");
469
470
471 if (status == GNUNET_VECTORPRODUCT_Status_Failure)
472 {
473 LOG (GNUNET_ERROR_TYPE_ERROR, "Requester Client received status failure\n");
474 ok = -1;
475 }
476 else if (status == GNUNET_VECTORPRODUCT_Status_InvalidResponse)
477 {
478 LOG (GNUNET_ERROR_TYPE_ERROR, "Requester Client received status invalid response\n");
479 ok = -1;
480 }
481 else if (GNUNET_VECTORPRODUCT_Status_Timeout == status)
482 {
483 LOG (GNUNET_ERROR_TYPE_ERROR, "Requester Client timeout occured\n");
484 ok = -1;
485 }
486 else if (GNUNET_VECTORPRODUCT_Status_ServiceDisconnected == status)
487 {
488 LOG (GNUNET_ERROR_TYPE_ERROR, "Requester Client service disconnected!!\n");
489 ok = -1;
490 }
491 else if (GNUNET_VECTORPRODUCT_Status_Success != status)
492 {
493 LOG (GNUNET_ERROR_TYPE_ERROR, "Requester Client Status = %d\n", (int) status);
494 ok = -1;
495 }
496 else if (GNUNET_VECTORPRODUCT_Status_Success == status)
497 {
498 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Requester client received status successful!\n");
499 product_len = ntohl (msg->product_length);
500
501 if (0 < product_len)
502 {
503 gcry_mpi_t result;
504 gcry_error_t ret = 0;
505 size_t read = 0;
506
507 ret = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, (void*) &(msg[1]), product_len, &read);
508
509 if (0 != ret)
510 {
511 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not convert to mpi to value!\n");
512 }
513 else
514 {
515 gcry_mpi_release (result);
516 }
517 ok = 1;
518 }
519 else
520 {
521 //currently not used, but if we get more info due to MESH we will need this
522 LOG (GNUNET_ERROR_TYPE_ERROR, "Error during computation of vector product, return code: %d\n", product_len);
523 ok = -1;
524 }
525 }
526
527 if (peer_->callback_num == 2)
528 GNUNET_SCHEDULER_add_now (&do_shutdown, peer_);
529}
530
531
532static struct GNUNET_VECTORPRODUCT_QueueEntry *
533requester_request (char * input_elements,
534 char * input_mask,
535 char * input_key,
536 struct PeerData * peer,
537 struct PeerData * to_peer)
538{
539
540
541 unsigned int i;
542 uint16_t element_count = 0;
543 int32_t * elements = NULL;
544 uint16_t mask_length = 0;
545 unsigned char * mask = NULL;
546 int32_t element;
547 struct GNUNET_VECTORPRODUCT_QueueEntry *qe;
548 struct GNUNET_HashCode key;
549 int exit_loop;
550 char * begin = input_elements;
551 char * end;
552
553 GNUNET_assert (peer->vh != NULL);
554
555 GNUNET_CRYPTO_hash_from_string (input_key, &key);
556
557 exit_loop = 0;
558 /* Read input_elements, and put in elements array */
559 do
560 {
561 unsigned int mcount = element_count;
562 //ignore empty rows of ,,,,,,
563 while (*begin == ',')
564 begin++;
565 // get the length of the current element and replace , with null
566 for (end = begin; *end && *end != ','; end++);
567
568 if (*end == '\0')
569 exit_loop = 1;
570
571
572 if (1 != sscanf (begin, "%" SCNd32, &element))
573 {
574 FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
575 ok = -1;
576 return NULL;
577 }
578
579 GNUNET_array_append (elements, mcount, element);
580 element_count++;
581
582 begin = ++end;
583 }
584 while (!exit_loop && element_count < max_mids);
585 GNUNET_assert (elements != NULL);
586 GNUNET_assert (element_count >= 1);
587
588 /* Read input_mask and read in mask array */
589 mask_length = element_count / 8 + (element_count % 8 ? 1 : 0);
590 mask = GNUNET_malloc ((element_count / 8) + 2);
591 GNUNET_assert (NULL != mask);
592 if (NULL != input_mask)
593 {
594 begin = input_mask;
595 unsigned short mask_count = 0;
596 int exit_loop = 0;
597
598 do
599 {
600 //ignore empty rows of ,,,,,,
601 while (* begin == ',')
602 begin++;
603 // get the length of the current element and replace , with null
604 // gnunet_ascii-armor uses base32, thus we can use , as separator!
605 for (end = begin; *end && *end != ','; end++);
606
607 if (*end == '\0')
608 exit_loop = 1;
609
610
611 if (1 != sscanf (begin, "%" SCNd32, &element))
612 {
613 FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
614 ok = -1;
615 return NULL;
616 }
617
618 GNUNET_assert (mask_count <= element_count);
619
620 if (element)
621 mask[mask_count / 8] = mask[mask_count / 8] | 1 << (mask_count % 8);
622
623 mask_count++;
624 begin = ++end;
625 }
626 while (!exit_loop);
627 // +1 to see if we would have more data, which would indicate malformed/superficial input
628 GNUNET_assert (mask_count == element_count);
629 }
630 else
631 {
632 for (i = 0; i <= mask_length; i++)
633 mask[i] = UCHAR_MAX; // all 1's
634 }
635
636 qe = GNUNET_VECTORPRODUCT_request (peer->vh,
637 &key,
638 &to_peer->our_id,
639 element_count,
640 mask_length,
641 elements, mask,
642 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60),
643 &requester_callback,
644 peer);
645
646 if (qe == NULL)
647 {
648 LOG(GNUNET_ERROR_TYPE_WARNING, "Could not send request to vectorproduct service! Exitting!");
649 ok = -1;
650 return NULL;
651 }
652
653 return qe;
654}
655
656
657/**
658 * Function prepares the message to be sent by peer1 to its vectorproduct service
659 * to prepare response, and wait for a request session to be initiated by peer1
660 */
661static struct GNUNET_VECTORPRODUCT_QueueEntry *
662responder_prepare_response (char * input_elements,
663 char * input_mask,
664 char * input_key,
665 struct PeerData * peer)
666{
667 GNUNET_assert (peer->vh != NULL);
668
669 unsigned int i;
670 uint16_t element_count = 0;
671 int32_t * elements = NULL;
672 unsigned short mask_length = 0;
673 unsigned char * mask = NULL;
674 int32_t element;
675 struct GNUNET_VECTORPRODUCT_QueueEntry *qe;
676 struct GNUNET_HashCode key;
677 int exit_loop;
678 char * begin;
679 char * end;
680
681 GNUNET_CRYPTO_hash_from_string (input_key, &key);
682
683 /* Read input_elements, and put in elements array */
684 exit_loop = 0;
685 begin = input_elements;
686 do
687 {
688 unsigned int mcount = element_count;
689 //ignore empty rows of ,,,,,,
690 while (*begin == ',')
691 begin++;
692 // get the length of the current element and replace , with null
693 for (end = begin; *end && *end != ','; end++);
694
695 if (*end == '\0')
696 exit_loop = 1;
697
698 if (1 != sscanf (begin, "%" SCNd32, &element))
699 {
700 FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
701 ok = -1;
702 return NULL;
703 }
704
705 GNUNET_array_append (elements, mcount, element);
706 element_count++;
707
708 begin = ++end;
709 }
710 while (!exit_loop && element_count < max_mids);
711 GNUNET_assert (elements != NULL);
712 GNUNET_assert (element_count >= 1);
713
714 /* Read input_mask and read in mask array */
715 mask_length = element_count / 8 + (element_count % 8 ? 1 : 0);
716 mask = GNUNET_malloc ((element_count / 8) + 2);
717 GNUNET_assert (NULL != mask);
718 if (NULL != input_mask)
719 {
720 begin = input_mask;
721 unsigned short mask_count = 0;
722 int exit_loop = 0;
723
724 do
725 {
726 //ignore empty rows of ,,,,,,
727 while (* begin == ',')
728 begin++;
729 // get the length of the current element and replace , with null
730 // gnunet_ascii-armor uses base32, thus we can use , as separator!
731 for (end = begin; *end && *end != ','; end++);
732
733 if (*end == '\0')
734 exit_loop = 1;
735
736 if (1 != sscanf (begin, "%" SCNd32, &element))
737 {
738 FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
739 ok = -1;
740 return NULL;
741 }
742
743 GNUNET_assert (mask_count <= element_count);
744
745 if (element)
746 mask[mask_count / 8] = mask[mask_count / 8] | 1 << (mask_count % 8);
747
748 mask_count++;
749 begin = ++end;
750 }
751 while (!exit_loop);
752 // +1 to see if we would have more data, which would indicate malformed/superficial input
753 GNUNET_assert (mask_count == element_count);
754 }
755 else
756 {
757 for (i = 0; i <= mask_length; i++)
758 mask[i] = UCHAR_MAX; // all 1's
759 }
760
761 qe = GNUNET_VECTORPRODUCT_prepare_response (peer->vh,
762 &key,
763 element_count,
764 elements,
765 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60),
766 &responder_callback,
767 peer);
768
769 if (qe == NULL)
770 {
771 LOG(GNUNET_ERROR_TYPE_ERROR, "Could not send request to vectorproduct service! Exitting!");
772 ok = -1;
773 return NULL;
774 }
775
776 return qe;
777}
778
779
780static void
781request_task (void *cls,
782 const struct GNUNET_SCHEDULER_TaskContext
783 * tc)
784{
785 struct PeerData * peer = cls;
786
787 requester_request (peer->input_elements, peer->input_mask, peer->input_keys[peer->request_num], peer, peer->peers[peer->request_num]);
788 peer->request_num++;
789 return;
790}
791
792
793static void
794prepare_response_task (void *cls,
795 const struct GNUNET_SCHEDULER_TaskContext
796 * tc)
797{
798 struct PeerData * peer = cls;
799
800 responder_prepare_response (peer->input_elements, peer->input_mask, peer->input_keys[peer->request_num], peer);
801 peer->request_num++;
802 return;
803}
804
805
806/**
807 * Adapter function called to destroy a connection to
808 * a service. This function is called when GNUNET_TESTBED_operation_done is
809 * called for peer->op, which holds the handle for GNUNET_TESTBED_service_connect
810 * operation.
811 *
812 * @param cls closure
813 * @param op_result service handle returned from the connect adapter
814 */
815static void
816vectorproduct_da (void *cls, void *op_result)
817{
818 struct PeerData* peer = (struct PeerData*) cls;
819
820 GNUNET_VECTORPRODUCT_disconnect (peer->vh);
821 return;
822
823 GNUNET_assert (0);
824}
825
826
827/**
828 * Adapter function called to establish a connection to
829 * a service. This function is called to by GNUNET_TESTBED_service_connect.
830 *
831 * @param cls closure
832 * @param cfg configuration of the peer to connect to; will be available until
833 * GNUNET_TESTBED_operation_done() is called on the operation returned
834 * from GNUNET_TESTBED_service_connect()
835 * @return service handle to return in 'op_result', NULL on error
836 */
837static void *
838vectorproduct_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
839{
840 struct PeerData *p = cls;
841
842 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", (&peer1 == p) ? 1 : 2,
843 GNUNET_i2s (&p->our_id));
844
845 switch (setup_state)
846 {
847 case PEER1_VECTORPRODUCT_CONNECT:
848 /* Connect peer 2 to vectorproduct service */
849 {
850 peer2.op = GNUNET_TESTBED_service_connect (&peer2, peer2.peer, "vectorproduct",
851 NULL, NULL, vectorproduct_ca,
852 vectorproduct_da, &peer2);
853 setup_state = PEER2_VECTORPRODUCT_CONNECT;
854 }
855
856 peer1.vh = GNUNET_VECTORPRODUCT_connect (cfg);
857 return peer1.vh;
858
859 case PEER2_VECTORPRODUCT_CONNECT:
860 /* Connect peer 3 to vectorproduct service */
861 {
862 peer3.op = GNUNET_TESTBED_service_connect (&peer3, peer3.peer, "vectorproduct",
863 NULL, NULL, vectorproduct_ca,
864 vectorproduct_da, &peer3);
865 setup_state = PEER3_VECTORPRODUCT_CONNECT;
866 }
867
868 peer2.vh = GNUNET_VECTORPRODUCT_connect (cfg);
869 return peer2.vh;
870
871 case PEER3_VECTORPRODUCT_CONNECT:
872 /* Connect peer 4 to vectorproduct service */
873 {
874 peer4.op = GNUNET_TESTBED_service_connect (&peer4, peer4.peer, "vectorproduct",
875 NULL, NULL, vectorproduct_ca,
876 vectorproduct_da, &peer4);
877 setup_state = PEER4_VECTORPRODUCT_CONNECT;
878 }
879
880 peer3.vh = GNUNET_VECTORPRODUCT_connect (cfg);
881 return peer3.vh;
882
883 case PEER4_VECTORPRODUCT_CONNECT:
884 peer4.vh = GNUNET_VECTORPRODUCT_connect (cfg);
885
886 /* Schedule the tasks to issue prepare_response calls from peer1 and peer2
887 * for peer3 and peer4.
888 */
889 GNUNET_SCHEDULER_add_now (&prepare_response_task, &peer1);
890 GNUNET_SCHEDULER_add_now (&prepare_response_task, &peer1);
891 GNUNET_SCHEDULER_add_now (&prepare_response_task, &peer2);
892 GNUNET_SCHEDULER_add_now (&prepare_response_task, &peer2);
893
894 /*
895 * Schedule the tasks to issue requests calls from peer3 and peer4
896 * to peer1 and peer2
897 */
898 GNUNET_SCHEDULER_add_now (&request_task, &peer3);
899 GNUNET_SCHEDULER_add_now (&request_task, &peer3);
900 GNUNET_SCHEDULER_add_now (&request_task, &peer4);
901 GNUNET_SCHEDULER_add_now (&request_task, &peer4);
902
903 return peer2.vh;
904 default:
905 GNUNET_assert (0);
906 }
907}
908
909
910/**
911 * Callback to be called when the requested peer information is available
912 *
913 * @param cb_cls the closure from GNUNET_TETSBED_peer_get_information()
914 * @param op the operation this callback corresponds to
915 * @param pinfo the result; will be NULL if the operation has failed
916 * @param emsg error message if the operation has failed; will be NULL if the
917 * operation is successfull
918 */
919static void
920peerinfo_cb (void *cb_cls, struct GNUNET_TESTBED_Operation *op_,
921 const struct GNUNET_TESTBED_PeerInformation *pinfo,
922 const char *emsg)
923{
924 GNUNET_assert (NULL == emsg);
925 GNUNET_assert (op == op_);
926 switch (setup_state)
927 {
928 case PEER1_GET_IDENTITY:
929 {
930 memcpy (&peer1.our_id, pinfo->result.id,
931 sizeof (struct GNUNET_PeerIdentity));
932 GNUNET_TESTBED_operation_done (op);
933
934 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 1 id: %s\n", GNUNET_i2s_full
935 (&peer1.our_id));
936
937 /* Request for peer id of peer 2*/
938 op = GNUNET_TESTBED_peer_get_information (peer2.peer,
939 GNUNET_TESTBED_PIT_IDENTITY,
940 &peerinfo_cb, NULL);
941 setup_state = PEER2_GET_IDENTITY;
942 }
943 break;
944 case PEER2_GET_IDENTITY:
945 {
946 memcpy (&peer2.our_id, pinfo->result.id,
947 sizeof (struct GNUNET_PeerIdentity));
948 GNUNET_TESTBED_operation_done (op);
949
950 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 2 id: %s\n", GNUNET_i2s_full
951 (&peer2.our_id));
952
953 /* Request for peer id of peer 3*/
954 op = GNUNET_TESTBED_peer_get_information (peer3.peer,
955 GNUNET_TESTBED_PIT_IDENTITY,
956 &peerinfo_cb, NULL);
957 setup_state = PEER3_GET_IDENTITY;
958 }
959 break;
960 case PEER3_GET_IDENTITY:
961 {
962 memcpy (&peer3.our_id, pinfo->result.id,
963 sizeof (struct GNUNET_PeerIdentity));
964 GNUNET_TESTBED_operation_done (op);
965
966 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 3 id: %s\n", GNUNET_i2s_full
967 (&peer3.our_id));
968
969 /* Request for peer id of peer 4*/
970 op = GNUNET_TESTBED_peer_get_information (peer4.peer,
971 GNUNET_TESTBED_PIT_IDENTITY,
972 &peerinfo_cb, NULL);
973 setup_state = PEER4_GET_IDENTITY;
974 }
975 break;
976 case PEER4_GET_IDENTITY:
977 {
978 memcpy (&peer4.our_id, pinfo->result.id,
979 sizeof (struct GNUNET_PeerIdentity));
980 GNUNET_TESTBED_operation_done (op);
981
982 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 2 id: %s\n", GNUNET_i2s_full
983 (&peer2.our_id));
984
985 /* Connect peer 1 to vectorproduct service */
986 peer1.op = GNUNET_TESTBED_service_connect (&peer1, peer1.peer, "vectorproduct",
987 NULL, NULL, vectorproduct_ca,
988 vectorproduct_da, &peer1);
989 setup_state = PEER1_VECTORPRODUCT_CONNECT;
990 }
991 break;
992 default:
993 GNUNET_assert (0);
994 }
995}
996
997
998/**
999 * Signature of a main function for a testcase.
1000 *
1001 * @param cls closure
1002 * @param num_peers number of peers in 'peers'
1003 * @param peers handle to peers run in the testbed
1004 */
1005static void
1006test_master (void *cls, unsigned int num_peers,
1007 struct GNUNET_TESTBED_Peer **peers)
1008{
1009 GNUNET_assert (NULL != peers);
1010 GNUNET_assert (NULL != peers[0]);
1011 GNUNET_assert (NULL != peers[1]);
1012 GNUNET_assert (NULL != peers[2]);
1013 GNUNET_assert (NULL != peers[3]);
1014 peer1.peer = peers[0];
1015 peer1.input_elements = input_elements_peer1;
1016 peer1.input_mask = input_mask_peer1;
1017 peer1.request_num = 0;
1018 peer1.callback_num = 0;
1019 peer1.input_keys[0] = input_key_p1_p3;
1020 peer1.input_keys[1] = input_key_p1_p4;
1021
1022 peer2.peer = peers[1];
1023 peer2.input_elements = input_elements_peer2;
1024 peer2.input_mask = input_mask_peer2;
1025 peer2.request_num = 0;
1026 peer2.callback_num = 0;
1027 peer2.input_keys[0] = input_key_p2_p3;
1028 peer2.input_keys[1] = input_key_p2_p4;
1029
1030 peer3.peer = peers[2];
1031 peer3.input_elements = input_elements_peer3;
1032 peer3.input_mask = input_mask_peer3;
1033 peer3.request_num = 0;
1034 peer3.callback_num = 0;
1035 peer3.input_keys[0] = input_key_p1_p3;
1036 peer3.input_keys[1] = input_key_p2_p3;
1037 peer3.peers[0] = &peer1;
1038 peer3.peers[1] = &peer2;
1039
1040
1041 peer4.peer = peers[3];
1042 peer4.input_elements = input_elements_peer4;
1043 peer4.input_mask = input_mask_peer4;
1044 peer4.request_num = 0;
1045 peer4.callback_num = 0;
1046 peer4.input_keys[0] = input_key_p1_p4;
1047 peer4.input_keys[1] = input_key_p2_p4;
1048 peer4.peers[0] = &peer1;
1049 peer4.peers[1] = &peer2;
1050
1051 /* Get the peer identity and configuration of peer 1 */
1052 op = GNUNET_TESTBED_peer_get_information (peer1.peer,
1053 GNUNET_TESTBED_PIT_IDENTITY,
1054 &peerinfo_cb, NULL);
1055 setup_state = PEER1_GET_IDENTITY;
1056 abort_task =
1057 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
1058 (GNUNET_TIME_UNIT_SECONDS, 120), &do_abort,
1059 NULL);
1060}
1061
1062
1063/**
1064 * Main function
1065 */
1066int
1067main (int argc, char **argv)
1068{
1069 uint64_t event_mask;
1070
1071 ok = GNUNET_NO;
1072 event_mask = 0;
1073 event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
1074 max_mids = (GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_MessageHeader))
1075 / sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1;
1076 (void) GNUNET_TESTBED_test_run ("test_vectorproduct_api_4peers",
1077 "test_vectorproduct_api_data.conf",
1078 NUM_PEERS, event_mask, &controller_event_cb,
1079 NULL,
1080 &test_master, NULL);
1081 if (GNUNET_SYSERR == ok)
1082 return 1;
1083 return 0;
1084}
diff --git a/src/vectorproduct/test_vectorproduct_api_data.conf b/src/vectorproduct/test_vectorproduct_api_data.conf
new file mode 100644
index 000000000..b0b1c257e
--- /dev/null
+++ b/src/vectorproduct/test_vectorproduct_api_data.conf
@@ -0,0 +1,96 @@
1[arm]
2DEFAULTSERVICES = core transport vectorproduct mesh testbed
3PORT = 12366
4
5[core]
6PORT = 12092
7
8[vectorproduct]
9#AUTOSTART = YES
10BINARY = gnunet-service-vectorproduct
11UNIXPATH = /tmp/gnunet-service-vectorproduct.sock
12HOME = $SERVICEHOME
13HOSTNAME = localhost
14PORT = 2087
15
16[testbed]
17OVERLAY_TOPOLOGY = CLIQUE
18
19[lockmanager]
20AUTOSTART = NO
21ACCEPT_FROM = 127.0.0.1;
22HOSTNAME = localhost
23PORT = 12101
24
25[statistics]
26AUTOSTART = YES
27ACCEPT_FROM = 127.0.0.1;
28PORT = 12102
29
30[fs]
31AUTOSTART = NO
32
33[resolver]
34AUTOSTART = NO
35
36[mesh]
37# AUTOSTART = YES
38ACCEPT_FROM = 127.0.0.1;
39HOSTNAME = localhost
40PORT = 10700
41# PREFIX = valgrind --leak-check=full
42# PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args
43
44[dht]
45AUTOSTART = YES
46ACCEPT_FROM6 = ::1;
47ACCEPT_FROM = 127.0.0.1;
48HOSTNAME = localhost
49PORT = 12100
50
51[block]
52plugins = dht test
53
54[dhtcache]
55QUOTA = 1 MB
56DATABASE = sqlite
57
58[transport]
59PLUGINS = tcp
60ACCEPT_FROM6 = ::1;
61ACCEPT_FROM = 127.0.0.1;
62NEIGHBOUR_LIMIT = 50
63PORT = 12365
64
65[ats]
66WAN_QUOTA_OUT = 3932160
67WAN_QUOTA_IN = 3932160
68
69[transport-tcp]
70TIMEOUT = 300 s
71PORT = 12368
72
73[TESTING]
74WEAKRANDOM = YES
75
76[gnunetd]
77HOSTKEY = $SERVICEHOME/.hostkey
78
79[PATHS]
80SERVICEHOME = /tmp/test-vectorproduct/
81
82[dns]
83AUTOSTART = NO
84
85[nse]
86AUTOSTART = NO
87
88[vpn]
89AUTOSTART = NO
90
91[nat]
92RETURN_LOCAL_ADDRESSES = YES
93
94[consensus]
95AUTOSTART = NO
96
diff --git a/src/vectorproduct/test_vectorproduct_api_regression.c b/src/vectorproduct/test_vectorproduct_api_regression.c
new file mode 100644
index 000000000..2bc0adec6
--- /dev/null
+++ b/src/vectorproduct/test_vectorproduct_api_regression.c
@@ -0,0 +1,852 @@
1
2/*
3 This file is part of GNUnet.
4 (C) 2013 Christian Grothoff (and other contributing authors)
5
6 GNUnet is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; either version 3, or (at your
9 option) any later version.
10
11 GNUnet is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNUnet; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
20 */
21
22/**
23 * @file vectorproduct/test_vectorproduct_api_regression.c
24 * @brief VectorProduct API regression test
25 * @author Gaurav Kukreja
26 * @author Christian Fuchs
27 */
28
29/**
30 * AIM of the regression test
31 *
32 * This test tries to check whether the service can handle abrupt client disconnect.
33 *
34 * 1. We create a responder peer, and ask the service to prepare_response. After this,
35 * we disconnect responder peer from service.
36 *
37 * 2. Then we create a requester peer, and ask service to request another peer. We
38 * should check that the service on responder peer is still active and receives
39 * request from the requester. We then disconnect requester peer from service. Both
40 * the requester and responder service should handle this cleanly.
41 */
42
43#include <string.h>
44
45#include <inttypes.h>
46#include "platform.h"
47#include "gnunet_util_lib.h"
48#include "gnunet_testbed_service.h"
49#include "gnunet_common.h"
50#include "gnunet_vectorproduct_service.h"
51#include "gnunet_protocols.h"
52
53#define LOG(kind,...) GNUNET_log_from (kind, "test-vectorproduct-api-regression",__VA_ARGS__)
54#define NUM_PEERS 2
55
56/**
57 * Structure for holding peer's sockets and IO Handles
58 */
59struct PeerData
60{
61 /**
62 * Handle to testbed peer
63 */
64 struct GNUNET_TESTBED_Peer *peer;
65
66 /**
67 * The service connect operation to stream
68 */
69 struct GNUNET_TESTBED_Operation *op;
70
71 /**
72 * Our Peer id
73 */
74 struct GNUNET_PeerIdentity our_id;
75
76 /**
77 * Pointer to Vector Product Handle
78 */
79 struct GNUNET_VECTORPRODUCT_Handle *vh;
80};
81
82/**
83 * Different states in test setup
84 */
85enum SetupState
86{
87 /**
88 * Get the identity of peer 1
89 */
90 PEER1_GET_IDENTITY,
91
92 /**
93 * Get the identity of peer 2
94 */
95 PEER2_GET_IDENTITY,
96
97 /**
98 * Connect to stream service of peer 1
99 */
100 PEER1_VECTORPRODUCT_CONNECT,
101
102 /**
103 * Connect to stream service of peer 2
104 */
105 PEER2_VECTORPRODUCT_CONNECT
106
107};
108
109/******************************************************************************
110 *** Global Variables *****************************
111 ******************************************************************************/
112
113/**
114 * Maximum allowed message-ids we can check in one go (with one GNUNET_message)
115 */
116static unsigned int max_mids;
117
118/**
119 * Session Key used by both the test peers
120 */
121char input_key[103] = "helloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhe";
122
123/**
124 * Input elements for peer1
125 */
126//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";
127char input_elements_peer1[] = "11,11,11";
128
129/**
130 * Input Mask for peer 1
131 */
132//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";
133char input_mask_peer1[] = "1,1,1";
134
135/**
136 * the array of converted message IDs to send to our service
137 */
138static int32_t * elements_peer1 = NULL;
139
140/**
141 * Input elements for peer2
142 */
143//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";
144char input_elements_peer2[] = "11,11,11";
145/**
146 * Input Mask for peer 2
147 */
148//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";
149char input_mask_peer2[] = "1,1,1";
150/**
151 * the array of converted message IDs to send to our service
152 */
153static int32_t * elements_peer2 = NULL;
154
155/**
156 * the array of converted message IDs to send to our service
157 */
158static unsigned char * mask_peer2 = NULL;
159
160/**
161 * Data context for peer 1
162 */
163static struct PeerData peer1;
164
165/**
166 * Data context for peer 2
167 */
168static struct PeerData peer2;
169
170/**
171 * Various states during test setup
172 */
173static enum SetupState setup_state;
174
175/**
176 * Testbed operation handle
177 */
178static struct GNUNET_TESTBED_Operation *op;
179
180/**
181 * Return value of the test.
182 */
183static int ok;
184
185/**
186 * Abort Task for timeout
187 */
188static GNUNET_SCHEDULER_TaskIdentifier abort_task;
189/******************************************************************************
190 *** Static Functions *****************************
191 ******************************************************************************/
192
193/**
194 * Helper function to shutdown a test peer
195 *
196 * @param cls void* to struct PeerData of the peer to be disconnected
197 * @param tc Task Context
198 */
199static void
200do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
201
202
203/**
204 * Helper function to connect a test peer
205 *
206 * @param cls void* to struct PeerData of the peer to be connected
207 * @param tc Task Context
208 */
209static void
210connect_peer (void *cls,
211 const struct GNUNET_SCHEDULER_TaskContext * tc);
212
213
214/**
215 * Close sockets and stop testing deamons nicely
216 */
217static void
218do_close (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
219{
220
221 if (peer1.op != NULL)
222 do_shutdown (&peer1, NULL);
223
224 if (peer2.op != NULL)
225 do_shutdown (&peer2, NULL);
226
227 if (GNUNET_SCHEDULER_NO_TASK != abort_task)
228 GNUNET_SCHEDULER_cancel (abort_task);
229
230 GNUNET_SCHEDULER_shutdown (); /* For shutting down testbed */
231}
232
233
234/**
235 * Helper function to shutdown a test peer
236 *
237 * @param cls void* to struct PeerData of the peer to be disconnected
238 * @param tc Task Context
239 */
240static void
241do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
242{
243 static int shutdown;
244 shutdown++;
245 struct PeerData* peer = (struct PeerData*) cls;
246
247 if (peer == &peer1)
248 LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting Peer1\n\n");
249 else if (peer == &peer2)
250 LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting Peer2\n\n");
251
252 // peer->op contains handle to the TESTBED_connect_service operation
253 // calling operation done, leads to call to vectorproduct_da
254 if (peer->op != NULL)
255 {
256 GNUNET_TESTBED_operation_done (peer->op);
257 peer->op = NULL;
258 }
259
260 if (shutdown >= 2)
261 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 10), &do_close, NULL);
262}
263
264
265/**
266 * Something went wrong and timed out. Kill everything and set error flag
267 */
268static void
269do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
270{
271 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: ABORT due to Timeout\n");
272 ok = GNUNET_SYSERR;
273 abort_task = 0;
274 do_close (cls, tc);
275}
276
277
278/**
279 * Controller event callback
280 *
281 * @param cls NULL
282 * @param event the controller event
283 */
284static void
285controller_event_cb (void *cls,
286 const struct GNUNET_TESTBED_EventInformation *event)
287{
288 switch (event->type)
289 {
290 case GNUNET_TESTBED_ET_OPERATION_FINISHED:
291 switch (setup_state)
292 {
293 case PEER1_VECTORPRODUCT_CONNECT:
294 case PEER2_VECTORPRODUCT_CONNECT:
295 GNUNET_assert (NULL == event->details.operation_finished.emsg);
296 break;
297 default:
298 GNUNET_assert (0);
299 }
300 break;
301 default:
302 GNUNET_assert (0);
303 }
304}
305
306
307/**
308 * Callback function called for the responder peer i.e. peer1
309 *
310 * @param cls
311 * @param key Session key
312 * @param status Status of the message
313 */
314static void
315responder_callback (void *cls,
316 const struct GNUNET_HashCode * key,
317 enum GNUNET_VECTORPRODUCT_ResponseStatus status)
318{
319 if (status == GNUNET_VECTORPRODUCT_Status_Failure)
320 {
321 LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received status failure\n");
322 ok = -1;
323 }
324 else if (status == GNUNET_VECTORPRODUCT_Status_InvalidResponse)
325 {
326 LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received status invalid response\n");
327 ok = -1;
328 }
329 else if (GNUNET_VECTORPRODUCT_Status_Timeout == status)
330 {
331 LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received timeout occured\n");
332 ok = -1;
333 }
334 else if (GNUNET_VECTORPRODUCT_Status_ServiceDisconnected == status)
335 {
336 LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received service disconnected!!\n");
337 ok = 1;
338 }
339 else if (GNUNET_VECTORPRODUCT_Status_Success == status)
340 {
341 LOG (GNUNET_ERROR_TYPE_DEBUG, "Responder Client expected response received!\n");
342 ok = -1;
343 }
344 else
345 {
346 LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client status = %d!\n", (int) status);
347 ok = -1;
348 }
349
350 // Not shutting down this time, only for this regression test. We have shutdown explicitly earlier.
351 // Shutting down again is causing problems.
352
353 // if(peer1.vh != NULL)
354 // {
355 // GNUNET_SCHEDULER_add_now(&do_shutdown, &peer1);
356 // }
357 return;
358}
359
360
361/**
362 * Callback function called for the requester peer i.e. peer2
363 *
364 * @param cls
365 * @param key Session key
366 * @param status Status of the message
367 */
368static void
369requester_callback (void *cls,
370 const struct GNUNET_HashCode * key,
371 const struct GNUNET_PeerIdentity * peer,
372 enum GNUNET_VECTORPRODUCT_ResponseStatus status,
373 const struct GNUNET_VECTORPRODUCT_client_response *msg)
374{
375 uint32_t product_len;
376
377 if (status == GNUNET_VECTORPRODUCT_Status_Failure)
378 {
379 LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client received status failure\n");
380 ok = -1;
381 }
382 else if (status == GNUNET_VECTORPRODUCT_Status_InvalidResponse)
383 {
384 LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client received status invalid response\n");
385 ok = -1;
386 }
387 else if (GNUNET_VECTORPRODUCT_Status_Timeout == status)
388 {
389 LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client timeout occured\n");
390 ok = -1;
391 }
392 else if (GNUNET_VECTORPRODUCT_Status_ServiceDisconnected == status)
393 {
394 LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client service disconnected!!\n");
395 ok = 1;
396 }
397 else if (GNUNET_VECTORPRODUCT_Status_Success != status)
398 {
399 LOG (GNUNET_ERROR_TYPE_DEBUG, "Requester Client Status = %d\n", (int) status);
400 ok = -1;
401 }
402 else if (GNUNET_VECTORPRODUCT_Status_Success == status)
403 {
404 product_len = ntohl (msg->product_length);
405
406 if (0 < product_len)
407 {
408 gcry_mpi_t result;
409 gcry_error_t ret = 0;
410 size_t read = 0;
411
412 ret = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, (void *) &msg[1], product_len, &read);
413
414 if (0 != ret)
415 {
416 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Could not convert to mpi to value!\n");
417 }
418 else
419 {
420 gcry_mpi_dump (result);
421 gcry_mpi_release (result);
422 }
423 ok = -1;
424 }
425 else
426 { //currently not used, but if we get more info due to MESH we will need this
427 LOG (GNUNET_ERROR_TYPE_WARNING, "Error during computation of vector product, return code: %d\n", product_len);
428 ok = -1;
429 }
430 }
431
432 // Not shutting down this time, only for this regression test. We have shutdown explicitly earlier.
433 // Shutting down again is causing problems.
434
435 // if(peer2.vh != NULL)
436 // {
437 // GNUNET_SCHEDULER_add_now(&do_shutdown, &peer2);
438 // }
439 return;
440}
441
442
443static void
444requester_request (void *cls,
445 const struct GNUNET_SCHEDULER_TaskContext * tc)
446{
447 GNUNET_assert (peer2.vh != NULL);
448
449 unsigned int i;
450 uint16_t element_count = 0;
451 uint16_t mask_length = 0;
452 char * begin = input_elements_peer2;
453 char * end;
454 int32_t element;
455 struct GNUNET_VECTORPRODUCT_QueueEntry *qe;
456 struct GNUNET_HashCode key;
457 int exit_loop = 0;
458
459 GNUNET_CRYPTO_hash (input_key, strlen (input_key), &key);
460
461 /* Read input_elements_peer2, and put in elements_peer2 array */
462 exit_loop = 0;
463 do
464 {
465 unsigned int mcount = element_count;
466 //ignore empty rows of ,,,,,,
467 while (*begin == ',')
468 begin++;
469 // get the length of the current element and replace , with null
470 for (end = begin; *end && *end != ','; end++);
471
472 if (*end == '\0')
473 exit_loop = 1;
474
475 if (1 != sscanf (begin, "%" SCNd32, &element))
476 {
477 FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
478 ok = -1;
479 return;
480 }
481
482 GNUNET_array_append (elements_peer2, mcount, element);
483 element_count++;
484
485 begin = ++end;
486 }
487 while (!exit_loop && element_count < max_mids);
488 GNUNET_assert (elements_peer2 != NULL);
489 GNUNET_assert (element_count >= 1);
490
491 /* Read input_mask_peer2 and read in mask_peer2 array */
492 mask_length = element_count / 8 + (element_count % 8 ? 1 : 0);
493 mask_peer2 = GNUNET_malloc ((element_count / 8) + 2);
494 GNUNET_assert (NULL != mask_peer2);
495 if (NULL != input_mask_peer2)
496 {
497 begin = input_mask_peer2;
498 unsigned short mask_count = 0;
499 exit_loop = 0;
500
501 do
502 {
503 //ignore empty rows of ,,,,,,
504 while (* begin == ',')
505 begin++;
506 // get the length of the current element and replace , with null
507 // gnunet_ascii-armor uses base32, thus we can use , as separator!
508 for (end = begin; *end && *end != ','; end++);
509
510 if (*end == '\0')
511 exit_loop = 1;
512
513 if (1 != sscanf (begin, "%" SCNd32, &element))
514 {
515 FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
516 ok = -1;
517 return;
518 }
519
520 GNUNET_assert (mask_count <= element_count);
521
522 if (element)
523 mask_peer2[mask_count / 8] = mask_peer2[mask_count / 8] | 1 << (mask_count % 8);
524
525 mask_count++;
526 begin = ++end;
527 }
528 while (!exit_loop);
529 // +1 to see if we would have more data, which would indicate malformed/superficial input
530 GNUNET_assert (mask_count == element_count);
531 }
532 else
533 {
534 for (i = 0; i <= mask_length; i++)
535 mask_peer2[i] = UCHAR_MAX; // all 1's
536 }
537
538 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Responder peer key %s\n", &peer1.our_id);
539
540 qe = GNUNET_VECTORPRODUCT_request (peer2.vh,
541 &key,
542 &peer1.our_id,
543 element_count,
544 mask_length,
545 elements_peer2, mask_peer2,
546 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
547 &requester_callback,
548 NULL);
549
550 if (qe == NULL)
551 {
552 FPRINTF (stderr, "%s", _ ("Could not send request to vectorproduct service! Exitting!"));
553 ok = -1;
554 return;
555 }
556
557 /**
558 * For regression, we shutdown the initiator peer, peer2, one second after
559 * issuing a request. Hopefully, peer1 notices that the tunnel has been
560 * been destroyed, and will shutdown cleanly.
561 */
562 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &do_shutdown, &peer2);
563
564 return;
565}
566
567
568/**
569 * Function prepares the message to be sent by peer1 to its vectorproduct service
570 * to prepare response, and wait for a request session to be initiated by peer1
571 */
572static void
573responder_prepare_response (void *cls,
574 const struct GNUNET_SCHEDULER_TaskContext * tc)
575{
576 GNUNET_assert (peer1.vh != NULL);
577
578 uint16_t element_count = 0;
579 char * begin = input_elements_peer1;
580 char * end;
581 int32_t element;
582
583 struct GNUNET_VECTORPRODUCT_QueueEntry *qe;
584
585 struct GNUNET_HashCode key;
586 GNUNET_CRYPTO_hash (input_key, strlen (input_key), &key);
587
588 int exit_loop = 0;
589 /* Read input_elements_peer1, and put in elements_peer1 array */
590 do
591 {
592 unsigned int mcount = element_count;
593 //ignore empty rows of ,,,,,,
594 while (*begin == ',')
595 begin++;
596 // get the length of the current element and replace , with null
597 for (end = begin; *end && *end != ','; end++);
598
599 if (*end == '\0')
600 exit_loop = 1;
601
602 if (1 != sscanf (begin, "%" SCNd32, &element))
603 {
604 FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
605 ok = -1;
606 return;
607 }
608
609 GNUNET_array_append (elements_peer1, mcount, element);
610 element_count++;
611
612 begin = ++end;
613 }
614 while (!exit_loop && element_count < max_mids);
615
616 GNUNET_assert (elements_peer1 != NULL);
617 GNUNET_assert (element_count >= 1);
618
619 qe = GNUNET_VECTORPRODUCT_prepare_response (peer1.vh,
620 &key,
621 element_count,
622 elements_peer1,
623 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
624 &responder_callback,
625 NULL);
626
627 if (qe == NULL)
628 {
629 FPRINTF (stderr, "%s", _ ("Could not send request to vectorproduct service! Exitting!"));
630 ok = -1;
631 return;
632 }
633
634 // connect the second peer
635 setup_state = PEER2_VECTORPRODUCT_CONNECT;
636 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1), &connect_peer, &peer2);
637
638 // while the service is waiting for a matching request, disconnect the test client
639 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &do_shutdown, &peer1);
640
641 return;
642}
643
644
645/**
646 * Adapter function called to destroy a connection to
647 * a service. This function is called when GNUNET_TESTBED_operation_done is
648 * called for peer->op, which holds the handle for GNUNET_TESTBED_service_connect
649 * operation.
650 *
651 * @param cls closure
652 * @param op_result service handle returned from the connect adapter
653 */
654static void
655vectorproduct_da (void *cls, void *op_result)
656{
657 struct PeerData* peer = (struct PeerData*) cls;
658
659 GNUNET_VECTORPRODUCT_disconnect (peer->vh);
660 peer->vh = NULL;
661 return;
662}
663
664
665/**
666 * Adapter function called to establish a connection to
667 * a service. This function is called to by GNUNET_TESTBED_service_connect.
668 *
669 * @param cls closure
670 * @param cfg configuration of the peer to connect to; will be available until
671 * GNUNET_TESTBED_operation_done() is called on the operation returned
672 * from GNUNET_TESTBED_service_connect()
673 * @return service handle to return in 'op_result', NULL on error
674 */
675static void *
676vectorproduct_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
677{
678 struct PeerData *p = cls;
679
680 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", (&peer1 == p) ? 1 : 2,
681 GNUNET_i2s (&p->our_id));
682
683 switch (setup_state)
684 {
685 case PEER1_VECTORPRODUCT_CONNECT:
686 peer1.vh = GNUNET_VECTORPRODUCT_connect (cfg);
687
688 if (peer1.vh != NULL)
689 {
690 /* prepare_response from peer1 */
691 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, &responder_prepare_response, NULL);
692 }
693 else
694 {
695 ok = -1;
696 return NULL;
697 }
698
699 return peer1.vh;
700
701 case PEER2_VECTORPRODUCT_CONNECT:
702 /* Actually connect peer 2 to vectorproduct service */
703 peer2.vh = GNUNET_VECTORPRODUCT_connect (cfg);
704
705 if (peer2.vh != NULL)
706 {
707 /* initiate request from peer2 */
708 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, &requester_request, NULL);
709 }
710 else
711 {
712 ok = -1;
713 return NULL;
714 }
715
716 return peer2.vh;
717 default:
718 GNUNET_assert (0);
719 }
720}
721
722
723/**
724 * Helper function to connect a test peer
725 *
726 * @param cls void* to struct PeerData of the peer to be connected
727 * @param tc Task Context
728 */
729static void
730connect_peer (void *cls,
731 const struct GNUNET_SCHEDULER_TaskContext * tc)
732{
733 struct PeerData *peer = cls;
734
735 peer->op = GNUNET_TESTBED_service_connect (peer, peer->peer, "vectorproduct",
736 NULL, NULL, vectorproduct_ca,
737 vectorproduct_da, peer);
738
739}
740
741
742/**
743 * Callback to be called when the requested peer information is available
744 *
745 * @param cb_cls the closure from GNUNET_TETSBED_peer_get_information()
746 * @param op the operation this callback corresponds to
747 * @param pinfo the result; will be NULL if the operation has failed
748 * @param emsg error message if the operation has failed; will be NULL if the
749 * operation is successfull
750 */
751static void
752peerinfo_cb (void *cb_cls, struct GNUNET_TESTBED_Operation *op_,
753 const struct GNUNET_TESTBED_PeerInformation *pinfo,
754 const char *emsg)
755{
756 GNUNET_assert (NULL == emsg);
757 GNUNET_assert (op == op_);
758
759 switch (setup_state)
760 {
761 case PEER1_GET_IDENTITY:
762 {
763 memcpy (&peer1.our_id, pinfo->result.id,
764 sizeof (struct GNUNET_PeerIdentity));
765 GNUNET_TESTBED_operation_done (op);
766
767 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 1 id: %s\n", GNUNET_i2s_full
768 (&peer1.our_id));
769
770 /* Request for peer id of peer 2*/
771 setup_state = PEER2_GET_IDENTITY;
772 op = GNUNET_TESTBED_peer_get_information (peer2.peer,
773 GNUNET_TESTBED_PIT_IDENTITY,
774 &peerinfo_cb, NULL);
775 }
776 break;
777 case PEER2_GET_IDENTITY:
778 {
779 memcpy (&peer2.our_id, pinfo->result.id,
780 sizeof (struct GNUNET_PeerIdentity));
781 GNUNET_TESTBED_operation_done (op);
782
783 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 2 id: %s\n", GNUNET_i2s_full
784 (&peer2.our_id));
785
786 /* Connect peer 1 to vectorproduct service */
787 setup_state = PEER1_VECTORPRODUCT_CONNECT;
788 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, &connect_peer, &peer1);
789 }
790 break;
791 default:
792 GNUNET_assert (0);
793 }
794}
795
796
797/**
798 * Signature of a main function for a testcase.
799 *
800 * @param cls closure
801 * @param num_peers number of peers in 'peers'
802 * @param peers handle to peers run in the testbed
803 */
804static void
805test_master (void *cls, unsigned int num_peers,
806 struct GNUNET_TESTBED_Peer **peers)
807{
808 GNUNET_assert (NULL != peers);
809 GNUNET_assert (NULL != peers[0]);
810 GNUNET_assert (NULL != peers[1]);
811 peer1.peer = peers[0];
812 peer2.peer = peers[1];
813
814 /* Get the peer identity and configuration of peer 1 */
815 setup_state = PEER1_GET_IDENTITY;
816 op = GNUNET_TESTBED_peer_get_information (peer1.peer,
817 GNUNET_TESTBED_PIT_IDENTITY,
818 &peerinfo_cb, NULL);
819
820 abort_task =
821 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
822 (GNUNET_TIME_UNIT_SECONDS, 20), &do_abort,
823 NULL);
824}
825
826
827/**
828 * Main function
829 */
830int
831main (int argc, char **argv)
832{
833 uint64_t event_mask;
834
835 ok = GNUNET_NO;
836 event_mask = 0;
837 event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
838 max_mids = (GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_MessageHeader))
839 / sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1;
840
841 (void) GNUNET_TESTBED_test_run ("test_vectorproduct_api_regression",
842 "test_vectorproduct_api_data.conf",
843 NUM_PEERS, event_mask, &controller_event_cb,
844 NULL,
845 &test_master, NULL);
846
847 if (GNUNET_SYSERR == ok)
848 return 1;
849 return 0;
850}
851
852
diff --git a/src/vectorproduct/test_vectorproduct_api_regression2.c b/src/vectorproduct/test_vectorproduct_api_regression2.c
new file mode 100644
index 000000000..8a0162b40
--- /dev/null
+++ b/src/vectorproduct/test_vectorproduct_api_regression2.c
@@ -0,0 +1,931 @@
1/*
2 This file is part of GNUnet.
3 (C) 2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
21/**
22 * @file vectorproduct/test_vectorproduct_api_regression2.c
23 * @brief Regression test, destroys requester service before receiving response
24 * responder service
25 * @author Gaurav Kukreja
26 * @author Christian Fuchs
27 */
28
29#include <string.h>
30
31#include <inttypes.h>
32#include "platform.h"
33#include "gnunet_util_lib.h"
34#include "gnunet_testbed_service.h"
35#include "gnunet_common.h"
36#include "gnunet_vectorproduct_service.h"
37#include "gnunet_protocols.h"
38
39#define LOG(kind,...) GNUNET_log_from (kind, "test-vectorproduct-api-regression2",__VA_ARGS__)
40#define NUM_PEERS 2
41
42/**
43 * Structure for holding peer's sockets and IO Handles
44 */
45struct PeerData
46{
47 /**
48 * Handle to testbed peer
49 */
50 struct GNUNET_TESTBED_Peer *peer;
51
52 /**
53 * The service connect operation to stream
54 */
55 struct GNUNET_TESTBED_Operation *op;
56
57 /**
58 * Our Peer id
59 */
60 struct GNUNET_PeerIdentity our_id;
61
62 /**
63 * Pointer to Vector Product Handle
64 */
65 struct GNUNET_VECTORPRODUCT_Handle *vh;
66};
67
68/**
69 * Different states in test setup
70 */
71enum SetupState
72{
73 /**
74 * Get the identity of peer 1
75 */
76 PEER1_GET_IDENTITY,
77
78 /**
79 * Get the identity of peer 2
80 */
81 PEER2_GET_IDENTITY,
82
83 /**
84 * Connect to stream service of peer 1
85 */
86 PEER1_VECTORPRODUCT_CONNECT,
87
88 /**
89 * Connect to stream service of peer 2
90 */
91 PEER2_VECTORPRODUCT_CONNECT
92
93};
94
95/******************************************************************************
96 *** Global Variables *****************************
97 ******************************************************************************/
98
99/**
100 * Maximum allowed message-ids we can check in one go (with one GNUNET_message)
101 */
102static unsigned int max_mids;
103
104/**
105 * Session Key used by both the test peers
106 */
107char input_key[103] = "helloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhe";
108
109/**
110 * Input elements for peer1
111 */
112char 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";
113//char input_elements_peer1[] = "11,11,11";
114
115/**
116 * Input Mask for peer 1
117 */
118char 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";
119//char input_mask_peer1[] = "1,1,1";
120
121/**
122 * the array of converted message IDs to send to our service
123 */
124static int32_t * elements_peer1 = NULL;
125
126/**
127 * the array of converted message IDs to send to our service
128 */
129static unsigned char * mask_peer1 = NULL;
130
131/**
132 * Number of elements
133 */
134uint16_t element_count_peer1 = 0;
135
136/**
137 * Input elements for peer2
138 */
139char 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";
140//char input_elements_peer2[] = "11,11,11";
141
142/**
143 * Input Mask for peer 2
144 */
145char 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";
146//char input_mask_peer2[] = "1,1,1";
147
148/**
149 * the array of converted message IDs to send to our service
150 */
151static int32_t * elements_peer2 = NULL;
152
153/**
154 * the array of converted message IDs to send to our service
155 */
156static unsigned char * mask_peer2 = NULL;
157
158/**
159 * Number of elements
160 */
161uint16_t element_count_peer2 = 0;
162
163/**
164 * Data context for peer 1
165 */
166static struct PeerData peer1;
167
168/**
169 * Data context for peer 2
170 */
171static struct PeerData peer2;
172
173/**
174 * Various states during test setup
175 */
176static enum SetupState setup_state;
177
178/**
179 * Testbed operation handle
180 */
181static struct GNUNET_TESTBED_Operation *op;
182
183static int ok;
184
185static int responder_ok;
186
187static int requester_ok;
188
189static GNUNET_SCHEDULER_TaskIdentifier abort_task;
190/******************************************************************************
191 *** Static Functions *****************************
192 ******************************************************************************/
193
194static void
195do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
196
197
198/**
199 * Close sockets and stop testing deamons nicely
200 */
201static void
202do_close (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
203{
204 static int closed;
205
206 if (peer1.op != NULL)
207 {
208 do_shutdown (&peer1, NULL);
209 }
210
211 if (peer2.op != NULL)
212 {
213 do_shutdown (&peer2, NULL);
214 }
215
216 if (GNUNET_SCHEDULER_NO_TASK != abort_task)
217 {
218 GNUNET_SCHEDULER_cancel (abort_task);
219 abort_task = GNUNET_SCHEDULER_NO_TASK;
220 GNUNET_SCHEDULER_shutdown (); /* For shutting down testbed */
221 }
222
223 if (!closed)
224 {
225 closed++;
226 GNUNET_SCHEDULER_shutdown (); /* For shutting down testbed */
227 }
228}
229
230/**
231 * Shutdown a peer
232 *
233 * @param cls closure is a pointer to the struct PeerData of the peer to be disconnected
234 * @param tc Task Context
235 */
236static void
237do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
238{
239 static int shutdown;
240 shutdown++;
241 struct PeerData* peer = (struct PeerData*) cls;
242
243 // peer->op contains handle to the TESTBED_connect_service operation
244 // calling operation done, leads to call to vectorproduct_da
245 if (peer->op != NULL)
246 {
247 if (peer == &peer1)
248 LOG (GNUNET_ERROR_TYPE_INFO, "Disconnecting Peer1\n\n");
249 else if (peer == &peer2)
250 LOG (GNUNET_ERROR_TYPE_INFO, "Disconnecting Peer2\n\n");
251
252 GNUNET_TESTBED_operation_done (peer->op);
253 peer->op = NULL;
254 }
255
256 if (peer1.op == NULL && peer2.op == NULL)
257 GNUNET_SCHEDULER_add_now (&do_close, NULL);
258}
259
260
261/**
262 * Something went wrong and timed out. Kill everything and set error flag
263 */
264static void
265do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
266{
267 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: ABORT due to Timeout\n");
268 ok = GNUNET_SYSERR;
269 abort_task = GNUNET_SCHEDULER_NO_TASK;
270 GNUNET_SCHEDULER_add_now (&do_shutdown, &peer1);
271 GNUNET_SCHEDULER_add_now (&do_shutdown, &peer2);
272}
273
274
275/**
276 * Controller event callback
277 *
278 * @param cls NULL
279 * @param event the controller event
280 */
281static void
282controller_event_cb (void *cls,
283 const struct GNUNET_TESTBED_EventInformation *event)
284{
285 switch (event->type)
286 {
287 case GNUNET_TESTBED_ET_OPERATION_FINISHED:
288 switch (setup_state)
289 {
290 case PEER1_VECTORPRODUCT_CONNECT:
291 case PEER2_VECTORPRODUCT_CONNECT:
292 GNUNET_assert (NULL == event->details.operation_finished.emsg);
293 break;
294 default:
295 GNUNET_assert (0);
296 }
297 break;
298 default:
299 GNUNET_assert (0);
300 }
301}
302
303
304static void
305responder_callback (void *cls,
306 const struct GNUNET_HashCode * key,
307 enum GNUNET_VECTORPRODUCT_ResponseStatus status)
308{
309 if (status == GNUNET_VECTORPRODUCT_Status_Failure)
310 {
311 LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received status failure\n");
312 responder_ok = -1;
313 }
314 else if (status == GNUNET_VECTORPRODUCT_Status_InvalidResponse)
315 {
316 LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received status invalid response\n");
317 responder_ok = -1;
318 }
319 else if (GNUNET_VECTORPRODUCT_Status_Timeout == status)
320 {
321 LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received timeout occured\n");
322 // In this regression test, requester is supposed to fail due to timeout
323 // therefore responder_ok is set to 1, to make regression test pass
324 responder_ok = 1;
325 }
326 else if (GNUNET_VECTORPRODUCT_Status_ServiceDisconnected == status)
327 {
328 LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client received service disconnected!!\n");
329 responder_ok = -1;
330 }
331 else if (GNUNET_VECTORPRODUCT_Status_Success == status)
332 {
333 LOG (GNUNET_ERROR_TYPE_DEBUG, "Responder Client expected response received!\n");
334 responder_ok = 1;
335 }
336 else
337 {
338 LOG (GNUNET_ERROR_TYPE_WARNING, "Responder Client status = %d!\n", (int) status);
339 responder_ok = -1;
340 }
341 // TODO : Responder Session Complete. Shutdown Test Cleanly!!!
342 //do_shutdown(&peer1, NULL);
343 GNUNET_SCHEDULER_add_now (&do_shutdown, &peer1);
344 return;
345}
346
347
348static void
349requester_callback (void *cls,
350 const struct GNUNET_HashCode * key,
351 const struct GNUNET_PeerIdentity * peer,
352 enum GNUNET_VECTORPRODUCT_ResponseStatus status,
353 uint16_t size, struct GNUNET_VECTORPRODUCT_client_response *msg,
354 uint16_t type)
355{
356 uint32_t product_len;
357
358 if (status == GNUNET_VECTORPRODUCT_Status_Failure)
359 {
360 LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client received status failure\n");
361 // In this regression test, requester is supposed to receive status failure
362 // therefore requester_ok is set to 1, to make regression test pass
363 requester_ok = 1;
364 }
365 else if (status == GNUNET_VECTORPRODUCT_Status_InvalidResponse)
366 {
367 LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client received status invalid response\n");
368 requester_ok = -1;
369 }
370 else if (GNUNET_VECTORPRODUCT_Status_Timeout == status)
371 {
372 LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client timeout occured\n");
373 requester_ok = -1;
374 }
375 else if (GNUNET_VECTORPRODUCT_Status_ServiceDisconnected == status)
376 {
377 LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client service disconnected!!\n");
378 requester_ok = -1;
379 }
380 else if (GNUNET_VECTORPRODUCT_Status_Success != status)
381 {
382 LOG (GNUNET_ERROR_TYPE_WARNING, "Requester Client Status = %d\n", (int) status);
383 requester_ok = -1;
384 }
385 else if (GNUNET_VECTORPRODUCT_Status_Success == status)
386 {
387 LOG (GNUNET_ERROR_TYPE_DEBUG, "Requester Client expected response received!\n");
388
389 product_len = ntohl (msg->product_length);
390
391 if (0 < product_len)
392 {
393 gcry_mpi_t result;
394 gcry_error_t ret = 0;
395 size_t read = 0;
396
397 ret = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, (void *) &msg[1], product_len, &read);
398
399 if (0 != ret)
400 {
401 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not convert to mpi to value!\n");
402 ok = -1;
403 }
404 else
405 {
406 uint16_t i = 0;
407
408 // calculate expected product
409 gcry_mpi_t expected_result;
410 gcry_mpi_t v1;
411 gcry_mpi_t v2;
412 gcry_mpi_t v1_v2_prod;
413
414 expected_result = gcry_mpi_new (0);
415
416 for (i = 0; i < element_count_peer1; i++)
417 {
418 uint32_t value;
419 v1_v2_prod = gcry_mpi_new (0);
420
421 // long to gcry_mpi_t
422 value = elements_peer1[i] >= 0 ? elements_peer1[i] : -elements_peer1[i];
423 if (elements_peer1[i] < 0)
424 {
425 v1 = gcry_mpi_new (0);
426 gcry_mpi_sub_ui (v1, v1, value);
427 }
428 else
429 v1 = gcry_mpi_set_ui (NULL, value);
430
431 // long to gcry_mpi_t
432 value = elements_peer2[i] >= 0 ? elements_peer2[i] : -elements_peer2[i];
433 if (elements_peer2[i] < 0)
434 {
435 v2 = gcry_mpi_new (0);
436 gcry_mpi_sub_ui (v2, v2, value);
437 }
438 else
439 v2 = gcry_mpi_set_ui (NULL, value);
440
441 gcry_mpi_mul (v1_v2_prod, v1, v2);
442 gcry_mpi_add (expected_result, expected_result, v1_v2_prod);
443
444 gcry_mpi_release (v1);
445 gcry_mpi_release (v2);
446 gcry_mpi_release (v1_v2_prod);
447
448 }
449
450 // compare the result
451 if (!gcry_mpi_cmp (expected_result, result))
452 {
453 LOG (GNUNET_ERROR_TYPE_DEBUG, "Scalar Product matches expected Result!!\n");
454 requester_ok = 1;
455 }
456 else
457 {
458 LOG (GNUNET_ERROR_TYPE_WARNING, "Scalar Product DOES NOT match expected Result!!\n");
459 requester_ok = -1;
460 }
461 gcry_mpi_release (result);
462 gcry_mpi_release (expected_result);
463 }
464 }
465 else
466 { //currently not used, but if we get more info due to MESH we will need this
467 LOG (GNUNET_ERROR_TYPE_WARNING, "Error during computation of vector product, return code: %d\n", product_len);
468 requester_ok = -1;
469 }
470 }
471
472 //do_shutdown(&peer2, NULL);
473 GNUNET_SCHEDULER_add_now (&do_shutdown, &peer2);
474 return;
475}
476
477
478static struct GNUNET_VECTORPRODUCT_QueueEntry *
479requester_request ()
480{
481 GNUNET_assert (peer2.vh != NULL);
482
483 unsigned int i;
484 //uint16_t element_count_peer2 = 0;
485 uint16_t mask_length = 0;
486 char * begin = input_elements_peer2;
487 char * end;
488 int32_t element;
489
490 struct GNUNET_VECTORPRODUCT_QueueEntry *qe;
491
492 struct GNUNET_HashCode key;
493 GNUNET_CRYPTO_hash (input_key, strlen (input_key), &key);
494
495 int exit_loop = 0;
496 /* Read input_elements_peer2, and put in elements_peer2 array */
497 do
498 {
499 unsigned int mcount = element_count_peer2;
500 //ignore empty rows of ,,,,,,
501 while (*begin == ',')
502 begin++;
503 // get the length of the current element and replace , with null
504 for (end = begin; *end && *end != ','; end++);
505
506 if (*end == '\0')
507 exit_loop = 1;
508
509 if (1 != sscanf (begin, "%" SCNd32, &element))
510 {
511 FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
512 ok = -1;
513 return NULL;
514 }
515
516 GNUNET_array_append (elements_peer2, mcount, element);
517 element_count_peer2++;
518
519 begin = ++end;
520 }
521 while (!exit_loop && element_count_peer2 < max_mids);
522
523 GNUNET_assert (elements_peer2 != NULL);
524 GNUNET_assert (element_count_peer2 >= 1);
525 mask_length = element_count_peer2 / 8 + (element_count_peer2 % 8 ? 1 : 0);
526 mask_peer2 = GNUNET_malloc ((element_count_peer2 / 8) + 2);
527 GNUNET_assert (NULL != mask_peer2);
528
529 /* Read input_mask_peer2 and read in mask_peer2 array */
530 if (NULL != input_mask_peer2)
531 {
532 begin = input_mask_peer2;
533 unsigned short mask_count = 0;
534 int exit_loop = 0;
535
536 do
537 {
538 //ignore empty rows of ,,,,,,
539 while (* begin == ',')
540 begin++;
541 // get the length of the current element and replace , with null
542 // gnunet_ascii-armor uses base32, thus we can use , as separator!
543 for (end = begin; *end && *end != ','; end++);
544
545 if (*end == '\0')
546 exit_loop = 1;
547
548 if (1 != sscanf (begin, "%" SCNd32, &element))
549 {
550 FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
551 ok = -1;
552 return NULL;
553 }
554
555 GNUNET_assert (mask_count <= element_count_peer2);
556
557 if (element)
558 mask_peer2[mask_count / 8] = mask_peer2[mask_count / 8] | 1 << (mask_count % 8);
559
560 mask_count++;
561 begin = ++end;
562 }
563 while (!exit_loop);
564 // +1 to see if we would have more data, which would indicate malformed/superficial input
565 GNUNET_assert (mask_count == element_count_peer2);
566 }
567 else
568 {
569 for (i = 0; i <= mask_length; i++)
570 mask_peer2[i] = UCHAR_MAX; // all 1's
571 }
572
573 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Responder peer key %s\n", &peer1.our_id);
574
575 // TODO : Create the mask array
576 qe = GNUNET_VECTORPRODUCT_request (peer2.vh,
577 &key,
578 &peer1.our_id,
579 element_count_peer2,
580 mask_length,
581 elements_peer2, mask_peer2,
582 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
583 &requester_callback,
584 NULL);
585
586 if (qe == NULL)
587 {
588 FPRINTF (stderr, "%s", _ ("Could not send request to vectorproduct service! Exitting!"));
589 ok = -1;
590 return NULL;
591 }
592
593 return qe;
594}
595
596
597/**
598 * Function prepares the message to be sent by peer1 to its vectorproduct service
599 * to prepare response, and wait for a request session to be initiated by peer1
600 */
601static struct GNUNET_VECTORPRODUCT_QueueEntry *
602responder_prepare_response ()
603{
604 GNUNET_assert (peer1.vh != NULL);
605
606 unsigned int i;
607 //uint16_t element_count_peer1 = 0;
608 char * begin = input_elements_peer1;
609 char * end;
610 int32_t element;
611
612 struct GNUNET_VECTORPRODUCT_QueueEntry *qe;
613
614 struct GNUNET_HashCode key;
615 GNUNET_CRYPTO_hash (input_key, strlen (input_key), &key);
616
617 int exit_loop = 0;
618 /* Read input_elements_peer1, and put in elements_peer1 array */
619 do
620 {
621 unsigned int mcount = element_count_peer1;
622 //ignore empty rows of ,,,,,,
623 while (*begin == ',')
624 begin++;
625 // get the length of the current element and replace , with null
626 for (end = begin; *end && *end != ','; end++);
627
628 if (*end == '\0')
629 exit_loop = 1;
630
631 if (*end == ',')
632 *end = '\0';
633
634 if (1 != sscanf (begin, "%" SCNd32, &element))
635 {
636 FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
637 ok = -1;
638 return NULL;
639 }
640
641 GNUNET_array_append (elements_peer1, mcount, element);
642 element_count_peer1++;
643
644 begin = ++end;
645 }
646 while (!exit_loop && element_count_peer1 < max_mids);
647
648 GNUNET_assert (elements_peer1 != NULL);
649 GNUNET_assert (element_count_peer1 >= 1);
650
651 qe = GNUNET_VECTORPRODUCT_prepare_response (peer1.vh,
652 &key,
653 element_count_peer1,
654 elements_peer1,
655 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
656 &responder_callback,
657 NULL);
658
659 if (qe == NULL)
660 {
661 FPRINTF (stderr, "%s", _ ("Could not send request to vectorproduct service! Exitting!"));
662 ok = -1;
663 return NULL;
664 }
665 return qe;
666}
667
668
669/**
670 * Scheduler task to initiate requester client
671 *
672 * @param cls void* to struct PeerData
673 * @param tc Task Context
674 */
675static void
676request_task (void *cls,
677 const struct GNUNET_SCHEDULER_TaskContext
678 * tc)
679{
680 struct PeerData * peer = cls;
681
682 requester_request ();
683 return;
684}
685
686
687/**
688 * Scheduler task to initiate responder client
689 *
690 * @param cls void* to struct PeerData
691 * @param tc Task Context
692 */
693static void
694prepare_response_task (void *cls,
695 const struct GNUNET_SCHEDULER_TaskContext
696 * tc)
697{
698 struct PeerData * peer = cls;
699
700 responder_prepare_response ();
701 return;
702}
703
704
705static void
706peer_stop_callback (void *cls,
707 const char *emsg)
708{
709 GNUNET_TESTBED_peer_destroy (peer2.peer);
710}
711
712/**
713 * Destroys Peer2 i.e. the initiator peer (Alice) This function is scheduled to
714 * run a few milliseconds after the request has been sent to the Responding Peer (Bob).
715 * This function tries to emulate a crash of Peer2.
716 *
717 * @param cls Not used
718 * @param tc Task Context - Not used
719 */
720static void
721destroy_server (void *cls,
722 const struct GNUNET_SCHEDULER_TaskContext *tc)
723{
724 LOG (GNUNET_ERROR_TYPE_INFO, "\n***\nKilling the Requesting Client, hopefully before it receives response\n***\n");
725 do_shutdown (&peer2, NULL);
726 GNUNET_TESTBED_peer_stop (peer2.peer, &peer_stop_callback, NULL);
727}
728
729
730/**
731 * Adapter function called to destroy a connection to
732 * a service. This function is called when GNUNET_TESTBED_operation_done is
733 * called for peer->op, which holds the handle for GNUNET_TESTBED_service_connect
734 * operation.
735 *
736 * @param cls closure
737 * @param op_result service handle returned from the connect adapter
738 */
739static void
740vectorproduct_da (void *cls, void *op_result)
741{
742 struct PeerData* peer = (struct PeerData*) cls;
743
744 GNUNET_VECTORPRODUCT_disconnect (peer->vh);
745 return;
746}
747
748
749/**
750 * Adapter function called to establish a connection to
751 * a service. This function is called to by GNUNET_TESTBED_service_connect.
752 *
753 * @param cls closure
754 * @param cfg configuration of the peer to connect to; will be available until
755 * GNUNET_TESTBED_operation_done() is called on the operation returned
756 * from GNUNET_TESTBED_service_connect()
757 * @return service handle to return in 'op_result', NULL on error
758 */
759static void *
760vectorproduct_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
761{
762 struct PeerData *p = cls;
763
764 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", (&peer1 == p) ? 1 : 2,
765 GNUNET_i2s (&p->our_id));
766
767 switch (setup_state)
768 {
769 case PEER1_VECTORPRODUCT_CONNECT:
770 /* Connect peer 2 to vectorproduct service */
771 /* The connect adapter vectorproduct_ca will be called to perform the actual connection */
772 {
773 peer2.op = GNUNET_TESTBED_service_connect (&peer2, peer2.peer, "vectorproduct",
774 NULL, NULL, vectorproduct_ca,
775 vectorproduct_da, &peer2);
776 setup_state = PEER2_VECTORPRODUCT_CONNECT;
777 }
778
779 /* Actually connect peer 1 to vectorproduct service */
780 peer1.vh = GNUNET_VECTORPRODUCT_connect (cfg);
781 return peer1.vh;
782
783 case PEER2_VECTORPRODUCT_CONNECT:
784 /* Actually connect peer 2 to vectorproduct service */
785 peer2.vh = GNUNET_VECTORPRODUCT_connect (cfg);
786
787
788 if (peer1.vh != NULL && peer2.vh != NULL)
789 {
790 GNUNET_SCHEDULER_add_now (&prepare_response_task, &peer1);
791 GNUNET_SCHEDULER_add_now (&request_task, &peer2);
792 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 6),
793 &destroy_server, NULL);
794 }
795 else
796 {
797 // TODO : Handle error. One of the peers is not connected. Cleanly shutdown
798 ok = -1;
799 return NULL;
800 }
801 return peer2.vh;
802 default:
803 GNUNET_assert (0);
804 }
805}
806
807
808/**
809 * Callback to be called when the requested peer information is available
810 *
811 * @param cb_cls the closure from GNUNET_TETSBED_peer_get_information()
812 * @param op the operation this callback corresponds to
813 * @param pinfo the result; will be NULL if the operation has failed
814 * @param emsg error message if the operation has failed; will be NULL if the
815 * operation is successfull
816 */
817static void
818peerinfo_cb (void *cb_cls, struct GNUNET_TESTBED_Operation *op_,
819 const struct GNUNET_TESTBED_PeerInformation *pinfo,
820 const char *emsg)
821{
822 GNUNET_assert (NULL == emsg);
823 GNUNET_assert (op == op_);
824 switch (setup_state)
825 {
826 case PEER1_GET_IDENTITY:
827 {
828 memcpy (&peer1.our_id, pinfo->result.id,
829 sizeof (struct GNUNET_PeerIdentity));
830 GNUNET_TESTBED_operation_done (op);
831
832 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 1 id: %s\n", GNUNET_i2s_full
833 (&peer1.our_id));
834
835 /* Request for peer id of peer 2*/
836 op = GNUNET_TESTBED_peer_get_information (peer2.peer,
837 GNUNET_TESTBED_PIT_IDENTITY,
838 &peerinfo_cb, NULL);
839 setup_state = PEER2_GET_IDENTITY;
840 }
841 break;
842 case PEER2_GET_IDENTITY:
843 {
844 memcpy (&peer2.our_id, pinfo->result.id,
845 sizeof (struct GNUNET_PeerIdentity));
846 GNUNET_TESTBED_operation_done (op);
847
848 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 2 id: %s\n", GNUNET_i2s_full
849 (&peer2.our_id));
850
851 /* Connect peer 1 to vectorproduct service */
852 /* The connect adapter vectorproduct_ca will be called to perform the actual connection */
853 peer1.op = GNUNET_TESTBED_service_connect (&peer1, peer1.peer, "vectorproduct",
854 NULL, NULL, vectorproduct_ca,
855 vectorproduct_da, &peer1);
856 setup_state = PEER1_VECTORPRODUCT_CONNECT;
857 }
858 break;
859 default:
860 GNUNET_assert (0);
861 }
862}
863
864
865/**
866 * Signature of a main function for a testcase.
867 *
868 * @param cls closure
869 * @param num_peers number of peers in 'peers'
870 * @param peers handle to peers run in the testbed
871 */
872static void
873test_master (void *cls, unsigned int num_peers,
874 struct GNUNET_TESTBED_Peer **peers)
875{
876 GNUNET_assert (NULL != peers);
877 GNUNET_assert (NULL != peers[0]);
878 GNUNET_assert (NULL != peers[1]);
879 peer1.peer = peers[0];
880 peer2.peer = peers[1];
881 /* Get the peer identity and configuration of peer 1 */
882 op = GNUNET_TESTBED_peer_get_information (peer1.peer,
883 GNUNET_TESTBED_PIT_IDENTITY,
884 &peerinfo_cb, NULL);
885 setup_state = PEER1_GET_IDENTITY;
886 abort_task =
887 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
888 (GNUNET_TIME_UNIT_SECONDS, 20), &do_abort,
889 NULL);
890}
891
892
893/**
894 * Main function
895 */
896int
897main (int argc, char **argv)
898{
899 uint64_t event_mask;
900
901 ok = GNUNET_NO;
902 event_mask = 0;
903 event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
904 max_mids = (GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_MessageHeader))
905 / sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1;
906
907 (void) GNUNET_TESTBED_test_run ("test_vectorproduct_api_regression2",
908 "test_vectorproduct_api_data.conf",
909 NUM_PEERS, event_mask, &controller_event_cb,
910 NULL,
911 &test_master, NULL);
912 if (GNUNET_SYSERR == ok)
913 {
914 LOG (GNUNET_ERROR_TYPE_ERROR, "Test failing due to some error before calling API for request or prepare_response\n");
915 return 1;
916 }
917 else if (GNUNET_SYSERR == responder_ok)
918 {
919 LOG (GNUNET_ERROR_TYPE_ERROR, "Test failing due to some error in response for responding_client\n");
920 return 1;
921 }
922 else if (GNUNET_SYSERR == requester_ok)
923 {
924 LOG (GNUNET_ERROR_TYPE_ERROR, "Test failing due to some error in response for requesting client\n");
925 return 1;
926 }
927 else
928 return 0;
929}
930
931
diff --git a/src/vectorproduct/vectorproduct.conf.in b/src/vectorproduct/vectorproduct.conf.in
new file mode 100644
index 000000000..e47af6f6a
--- /dev/null
+++ b/src/vectorproduct/vectorproduct.conf.in
@@ -0,0 +1,7 @@
1[vectorproduct]
2BINARY = gnunet-service-vectorproduct
3UNIXPATH = /tmp/gnunet-service-vectorproduct.sock
4HOME = $SERVICEHOME
5# PORT = 2106
6@UNIXONLY@ PORT = 2087
7
diff --git a/src/vectorproduct/vectorproduct_api.c b/src/vectorproduct/vectorproduct_api.c
new file mode 100644
index 000000000..4f8cde8fe
--- /dev/null
+++ b/src/vectorproduct/vectorproduct_api.c
@@ -0,0 +1,715 @@
1/*
2 This file is part of GNUnet.
3 (C) 2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
21/**
22 * @file vectorproduct/vectorproduct_api.c
23 * @brief API for the vectorproduct
24 * @author Christian Fuchs
25 * @author Gaurav Kukreja
26 *
27 */
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_statistics_service.h"
31#include "gnunet_vectorproduct_service.h"
32#include "gnunet_protocols.h"
33
34#define LOG(kind,...) GNUNET_log_from (kind, "vectorproduct-api",__VA_ARGS__)
35
36/**************************************************************
37 *** Datatype Declarations **********
38 **************************************************************/
39
40/**
41 * Entry in the request queue per client
42 */
43struct GNUNET_VECTORPRODUCT_QueueEntry
44{
45 /**
46 * This is a linked list.
47 */
48 struct GNUNET_VECTORPRODUCT_QueueEntry *next;
49
50 /**
51 * This is a linked list.
52 */
53 struct GNUNET_VECTORPRODUCT_QueueEntry *prev;
54
55 /**
56 * Handle to the master context.
57 */
58 struct GNUNET_VECTORPRODUCT_Handle *h;
59
60 /**
61 * Size of the message
62 */
63 uint16_t message_size;
64
65 /**
66 * Message to be sent to the vectorproduct service
67 */
68 struct GNUNET_VECTORPRODUCT_client_request* msg;
69
70 union
71 {
72 /**
73 * Function to call after transmission of the request.
74 */
75 GNUNET_VECTORPRODUCT_ContinuationWithStatus cont_status;
76
77 /**
78 * Function to call after transmission of the request.
79 */
80 GNUNET_VECTORPRODUCT_DatumProcessor cont_datum;
81 };
82
83 /**
84 * Closure for 'cont'.
85 */
86 void *cont_cls;
87
88 /**
89 * Has this message been transmitted to the service?
90 * Only ever GNUNET_YES for the head of the queue.
91 * Note that the overall struct should end at a
92 * multiple of 64 bits.
93 */
94 int16_t was_transmitted;
95
96 /**
97 * Timeout for the current operation.
98 */
99 struct GNUNET_TIME_Absolute timeout;
100
101 /**
102 * Task for timeout signaling.
103 */
104 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
105
106 /**
107 * Response Processor for response from the service. This function calls the
108 * continuation function provided by the client.
109 */
110 GNUNET_VECTORPRODUCT_ResponseMessageHandler response_proc;
111};
112
113/**************************************************************
114 *** Function Declarations **********
115 **************************************************************/
116
117/**
118 * Creates a new entry at the tail of the DLL
119 *
120 * @param h handle to the master context
121 *
122 * @return pointer to the entry
123 */
124static struct GNUNET_VECTORPRODUCT_QueueEntry *
125make_queue_entry (struct GNUNET_VECTORPRODUCT_Handle *h);
126
127/**
128 * Removes the head entry from the queue
129 *
130 * @param h Handle to the master context
131 */
132static struct GNUNET_VECTORPRODUCT_QueueEntry *
133free_queue_head_entry (struct GNUNET_VECTORPRODUCT_Handle * h);
134
135/**
136 * Triggered when timeout occurs for a request in queue
137 *
138 * @param cls The pointer to the QueueEntry
139 * @param tc Task Context
140 */
141static void
142timeout_queue_entry (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
143
144/**
145 * Called when a response is received from the service. After basic check
146 * handler in qe->response_proc is called. This functions handles the response
147 * to the client which used the API.
148 *
149 * @param cls Pointer to the Master Context
150 * @param msg Pointer to the data received in response
151 */
152static void
153receive_cb (void *cls, const struct GNUNET_MessageHeader *msg);
154
155/**
156 * Transmits the request to the VectorProduct Sevice
157 *
158 * @param cls Closure
159 * @param size Size of the buffer
160 * @param buf Pointer to the buffer
161 *
162 * @return Size of the message sent
163 */
164static size_t transmit_request (void *cls, size_t size,
165 void *buf);
166
167/**
168 * Issues transmit request for the new entries in the queue
169 *
170 * @param h handle to the master context
171 */
172static void
173process_queue (struct GNUNET_VECTORPRODUCT_Handle *h);
174
175/**************************************************************
176 *** Static Function Declarations **********
177 **************************************************************/
178
179
180/**
181 * Creates a new entry at the tail of the DLL
182 *
183 * @param h handle to the master context
184 *
185 * @return pointer to the entry
186 */
187static struct GNUNET_VECTORPRODUCT_QueueEntry *
188make_queue_entry (struct GNUNET_VECTORPRODUCT_Handle *h)
189{
190 struct GNUNET_VECTORPRODUCT_QueueEntry *qe;
191
192 qe = GNUNET_new (struct GNUNET_VECTORPRODUCT_QueueEntry);
193
194 // if queue empty
195 if (NULL == h->queue_head && NULL == h->queue_tail)
196 {
197 qe->next = NULL;
198 qe->prev = NULL;
199 h->queue_head = qe;
200 h->queue_tail = qe;
201 }
202 else
203 {
204 qe->prev = h->queue_tail;
205 h->queue_tail->next = qe;
206 h->queue_tail = qe;
207 }
208
209 return qe;
210}
211
212
213/**
214 * Removes the head entry from the queue
215 *
216 * @param h Handle to the master context
217 */
218static struct GNUNET_VECTORPRODUCT_QueueEntry *
219free_queue_head_entry (struct GNUNET_VECTORPRODUCT_Handle * h)
220{
221 struct GNUNET_VECTORPRODUCT_QueueEntry * qe = NULL;
222
223 GNUNET_assert (NULL != h);
224 if (NULL == h->queue_head && NULL == h->queue_tail)
225 {
226 // The queue is empty. Just return.
227 LOG (GNUNET_ERROR_TYPE_DEBUG, "Queue was empty when free_queue_head_entry was called.\n");
228 }
229 else if (h->queue_head == h->queue_tail) //only one entry
230 {
231 qe = h->queue_head;
232 qe->next = NULL;
233 qe->prev = NULL;
234 h->queue_head = NULL;
235 h->queue_tail = NULL;
236 }
237 else
238 {
239 qe = h->queue_head;
240 h->queue_head = h->queue_head->next;
241 h->queue_head->prev = NULL;
242 qe->next = NULL;
243 qe->prev = NULL;
244 }
245 return qe;
246}
247
248
249/**
250 * Triggered when timeout occurs for a request in queue
251 *
252 * @param cls The pointer to the QueueEntry
253 * @param tc Task Context
254 */
255static void
256timeout_queue_entry (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
257{
258 struct GNUNET_VECTORPRODUCT_QueueEntry * qe = cls;
259
260 // Update Statistics
261 GNUNET_STATISTICS_update (qe->h->stats,
262 gettext_noop ("# queue entry timeouts"), 1,
263 GNUNET_NO);
264
265 // Clear the timeout_task
266 qe->timeout_task = GNUNET_SCHEDULER_NO_TASK;
267
268 // transmit_request is supposed to cancel timeout task.
269 // If message was not transmitted, there is definitely an error.
270 GNUNET_assert (GNUNET_NO == qe->was_transmitted);
271
272 LOG (GNUNET_ERROR_TYPE_INFO, "Timeout of request in datastore queue\n");
273
274 // remove the queue_entry for the queue
275 GNUNET_CONTAINER_DLL_remove (qe->h->queue_head, qe->h->queue_tail, qe);
276 qe->response_proc (qe, NULL, GNUNET_VECTORPRODUCT_Status_Timeout);
277}
278
279
280/**
281 * Handles the RESULT received in reply of prepare_response from the
282 * service
283 *
284 * @param cls Handle to the Master Context
285 * @param msg Pointer to the response received
286 */
287static void
288process_status_message (void *cls,
289 const struct GNUNET_MessageHeader *msg,
290 enum GNUNET_VECTORPRODUCT_ResponseStatus status)
291{
292 struct GNUNET_VECTORPRODUCT_QueueEntry *qe = cls;
293
294 GNUNET_assert (qe != NULL);
295
296 if (qe->cont_status != NULL)
297 qe->cont_status (qe->cont_cls, &qe->msg->key, status);
298}
299
300
301/**
302 * Handles the RESULT received in reply of prepare_response from the
303 * service
304 *
305 * @param cls Handle to the Master Context
306 * @param msg Pointer to the response received
307 */
308static void
309process_result_message (void *cls,
310 const struct GNUNET_MessageHeader *msg,
311 enum GNUNET_VECTORPRODUCT_ResponseStatus status)
312{
313 struct GNUNET_VECTORPRODUCT_QueueEntry *qe = cls;
314
315 GNUNET_assert (qe != NULL);
316
317 if (msg == NULL && qe->cont_datum != NULL)
318 {
319 LOG (GNUNET_ERROR_TYPE_DEBUG, "Timeout reached or session terminated.\n");
320 }
321 if (qe->cont_datum != NULL)
322 {
323 qe->cont_datum (qe->cont_cls, &qe->msg->key, &qe->msg->peer, status, (struct GNUNET_VECTORPRODUCT_client_response *) msg);
324 }
325}
326
327
328/**
329 * Called when a response is received from the service. After basic check
330 * handler in qe->response_proc is called. This functions handles the response
331 * to the client which used the API.
332 *
333 * @param cls Pointer to the Master Context
334 * @param msg Pointer to the data received in response
335 */
336static void
337receive_cb (void *cls, const struct GNUNET_MessageHeader *msg)
338{
339 struct GNUNET_VECTORPRODUCT_Handle *h = cls;
340 struct GNUNET_VECTORPRODUCT_QueueEntry *qe;
341 int16_t was_transmitted;
342 struct GNUNET_VECTORPRODUCT_client_response *message =
343 (struct GNUNET_VECTORPRODUCT_client_response *) msg;
344
345 h->in_receive = GNUNET_NO;
346 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received reply from VectorProduct\n");
347
348 if (NULL == (qe = free_queue_head_entry (h)))
349 {
350 /**
351 * The queue head will be NULL if the client disconnected,
352 * * In case of Alice, client disconnected after sending request, before receiving response
353 * * In case of Bob, client disconnected after preparing response, before getting request from Alice.
354 */
355 process_queue (h);
356 return;
357 }
358
359 if (h->client == NULL)
360 {
361 // GKUKREJA : handle this correctly
362 /**
363 * The queue head will be NULL if the client disconnected,
364 * * In case of Alice, client disconnected after sending request, before receiving response
365 * * In case of Bob, client disconnected after preparing response, before getting request from Alice.
366 */
367 process_queue (h);
368 return;
369 }
370
371 was_transmitted = qe->was_transmitted;
372 // Control will only come here, when the request was transmitted to service,
373 // and service responded.
374 GNUNET_assert (was_transmitted == GNUNET_YES);
375
376 if (msg == NULL)
377 {
378 LOG (GNUNET_ERROR_TYPE_WARNING, "Service responded with NULL!\n");
379 qe->response_proc (qe, NULL, GNUNET_VECTORPRODUCT_Status_Failure);
380 }
381 else if ((ntohs (msg->type) != GNUNET_MESSAGE_TYPE_VECTORPRODUCT_SERVICE_TO_CLIENT))
382 {
383 LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid Message Received\n");
384 qe->response_proc (qe, msg, GNUNET_VECTORPRODUCT_Status_InvalidResponse);
385 }
386 else if (ntohl (message->product_length) == 0)
387 {
388 // response for the responder client, successful
389 GNUNET_STATISTICS_update (h->stats,
390 gettext_noop ("# SUC responder result messages received"), 1,
391 GNUNET_NO);
392
393 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received message from service without product attached.\n");
394 qe->response_proc (qe, msg, GNUNET_VECTORPRODUCT_Status_Success);
395 }
396 else if (ntohl (message->product_length) > 0)
397 {
398 // response for the requester client, successful
399 GNUNET_STATISTICS_update (h->stats,
400 gettext_noop ("# SUC requester result messages received"), 1,
401 GNUNET_NO);
402
403 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received message from requester service for requester client.\n");
404 qe->response_proc (qe, msg, GNUNET_VECTORPRODUCT_Status_Success);
405 }
406
407 GNUNET_free (qe);
408 process_queue (h);
409}
410
411
412/**
413 * Transmits the request to the VectorProduct Sevice
414 *
415 * @param cls Closure
416 * @param size Size of the buffer
417 * @param buf Pointer to the buffer
418 *
419 * @return Size of the message sent
420 */
421static size_t
422transmit_request (void *cls, size_t size,
423 void *buf)
424{
425 struct GNUNET_VECTORPRODUCT_Handle *h = cls;
426 struct GNUNET_VECTORPRODUCT_QueueEntry *qe;
427 size_t msize;
428
429 if (NULL == (qe = h->queue_head))
430 {
431 LOG (GNUNET_ERROR_TYPE_DEBUG, "Queue head is NULL!\n\n");
432 return 0;
433 }
434
435 GNUNET_SCHEDULER_cancel (qe->timeout_task);
436 qe->timeout_task = GNUNET_SCHEDULER_NO_TASK;
437
438 h->th = NULL;
439 if (NULL == (qe = h->queue_head))
440 return 0; /* no entry in queue */
441 if (buf == NULL)
442 {
443 LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to transmit request to VECTORPRODUCT.\n");
444 GNUNET_STATISTICS_update (h->stats,
445 gettext_noop ("# transmission request failures"),
446 1, GNUNET_NO);
447 GNUNET_VECTORPRODUCT_disconnect (h);
448 return 0;
449 }
450 if (size < (msize = qe->message_size))
451 {
452 process_queue (h);
453 return 0;
454 }
455 LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting %u byte request to VECTORPRODUCT\n",
456 msize);
457
458 memcpy (buf, qe->msg, size);
459 GNUNET_free (qe->msg);
460 qe->was_transmitted = GNUNET_YES;
461
462 GNUNET_assert (GNUNET_NO == h->in_receive);
463 h->in_receive = GNUNET_YES;
464
465 GNUNET_CLIENT_receive (h->client, &receive_cb, h,
466 GNUNET_TIME_UNIT_FOREVER_REL);
467
468#if INSANE_STATISTICS
469 GNUNET_STATISTICS_update (h->stats,
470 gettext_noop ("# bytes sent to vectorproduct"), 1,
471 GNUNET_NO);
472#endif
473 return size;
474}
475
476
477/**
478 * Issues transmit request for the new entries in the queue
479 *
480 * @param h handle to the master context
481 */
482static void
483process_queue (struct GNUNET_VECTORPRODUCT_Handle *h)
484{
485 struct GNUNET_VECTORPRODUCT_QueueEntry *qe;
486
487 if (NULL == (qe = h->queue_head))
488 {
489 LOG (GNUNET_ERROR_TYPE_DEBUG, "Queue empty\n");
490 return; /* no entry in queue */
491 }
492 if (qe->was_transmitted == GNUNET_YES)
493 {
494 LOG (GNUNET_ERROR_TYPE_DEBUG, "Head request already transmitted\n");
495 return; /* waiting for replies */
496 }
497 if (h->th != NULL)
498 {
499 LOG (GNUNET_ERROR_TYPE_DEBUG, "Pending transmission request\n");
500 return; /* request pending */
501 }
502 if (h->client == NULL)
503 {
504 LOG (GNUNET_ERROR_TYPE_DEBUG, "Not connected\n");
505 return; /* waiting for reconnect */
506 }
507 if (GNUNET_YES == h->in_receive)
508 {
509 /* wait for response to previous query */
510 return;
511 }
512
513 h->th =
514 GNUNET_CLIENT_notify_transmit_ready (h->client, qe->message_size,
515 GNUNET_TIME_UNIT_FOREVER_REL,
516 GNUNET_YES,
517 &transmit_request, h);
518
519 if (h->th == NULL)
520 {
521 LOG (GNUNET_ERROR_TYPE_ERROR,
522 _ ("Failed to send a message to the vectorproduct service\n"));
523 return;
524 }
525
526 GNUNET_assert (GNUNET_NO == h->in_receive);
527 GNUNET_break (NULL != h->th);
528}
529
530
531
532/**************************************************************
533 *** API **********
534 **************************************************************/
535
536
537/**
538 * Called by the responder client to prepare response
539 *
540 * @param h handle to the master context
541 * @param key Session key - unique to the requesting client
542 * @param element_count Number of elements in the vector
543 * @param mask_length number of bytes in the mask
544 * @param elements Array of elements of the vector
545 * @param mask Array of the mask
546 * @param timeout Relative timeout for the operation
547 * @param cont Callback function
548 * @param cont_cls Closure for the callback function
549 */
550struct GNUNET_VECTORPRODUCT_QueueEntry *
551GNUNET_VECTORPRODUCT_prepare_response (struct GNUNET_VECTORPRODUCT_Handle *h,
552 const struct GNUNET_HashCode * key,
553 uint16_t element_count,
554 int32_t * elements,
555 struct GNUNET_TIME_Relative timeout,
556 GNUNET_VECTORPRODUCT_ContinuationWithStatus cont,
557 void *cont_cls)
558{
559 struct GNUNET_VECTORPRODUCT_QueueEntry *qe = make_queue_entry (h);
560 int32_t * vector;
561 uint16_t size;
562 unsigned int i;
563
564 GNUNET_assert (GNUNET_SERVER_MAX_MESSAGE_SIZE >= sizeof (struct GNUNET_VECTORPRODUCT_client_request)
565 +element_count * sizeof (int32_t));
566 size = sizeof (struct GNUNET_VECTORPRODUCT_client_request) +element_count * sizeof (int32_t);
567
568 qe->message_size = size;
569 qe->msg = GNUNET_malloc (size);
570 qe->msg->header.size = htons (size);
571 qe->msg->header.type = htons (GNUNET_MESSAGE_TYPE_VECTORPRODUCT_CLIENT_TO_BOB);
572 qe->msg->element_count = htons (element_count);
573 qe->msg->mask_length = htons (0);
574 memcpy (&qe->msg->key, key, sizeof (struct GNUNET_HashCode));
575 qe->cont_status = cont;
576 qe->cont_cls = cont_cls;
577 qe->was_transmitted = GNUNET_NO;
578 qe->timeout_task = GNUNET_SCHEDULER_add_delayed (timeout, &timeout_queue_entry, qe);
579 qe->response_proc = &process_status_message;
580 qe->timeout = GNUNET_TIME_relative_to_absolute (timeout);
581
582 vector = (int32_t *) & qe->msg[1];
583 // copy each element over to the message
584 for (i = 0; i < element_count; i++)
585 vector[i] = htonl (elements[i]);
586
587 process_queue (h);
588 return qe;
589}
590
591
592/**
593 * Request the Scalar Product Evaluation
594 *
595 * @param h handle to the master context
596 * @param key Session key - unique to the requesting client
597 * @param peer PeerID of the other peer
598 * @param element_count Number of elements in the vector
599 * @param mask_length number of bytes in the mask
600 * @param elements Array of elements of the vector
601 * @param mask Array of the mask
602 * @param timeout Relative timeout for the operation
603 * @param cont Callback function
604 * @param cont_cls Closure for the callback function
605 */
606struct GNUNET_VECTORPRODUCT_QueueEntry *
607GNUNET_VECTORPRODUCT_request (struct GNUNET_VECTORPRODUCT_Handle *h,
608 const struct GNUNET_HashCode * key,
609 const struct GNUNET_PeerIdentity * peer,
610 uint16_t element_count,
611 uint16_t mask_length,
612 int32_t * elements,
613 const unsigned char * mask,
614 struct GNUNET_TIME_Relative timeout,
615 GNUNET_VECTORPRODUCT_DatumProcessor cont,
616 void *cont_cls)
617{
618 struct GNUNET_VECTORPRODUCT_QueueEntry *qe = make_queue_entry (h);
619 int32_t * vector;
620 uint16_t size;
621 unsigned int i;
622
623 GNUNET_assert (GNUNET_SERVER_MAX_MESSAGE_SIZE >= sizeof (struct GNUNET_VECTORPRODUCT_client_request)
624 +element_count * sizeof (int32_t)
625 + mask_length);
626 size = sizeof (struct GNUNET_VECTORPRODUCT_client_request) +element_count * sizeof (int32_t) + mask_length;
627
628 qe->message_size = size;
629 qe->msg = GNUNET_malloc (size);
630 qe->msg->header.size = htons (size);
631 qe->msg->header.type = htons (GNUNET_MESSAGE_TYPE_VECTORPRODUCT_CLIENT_TO_ALICE);
632 memcpy (&qe->msg->peer, peer, sizeof (struct GNUNET_PeerIdentity));
633 qe->msg->element_count = htons (element_count);
634 qe->msg->mask_length = htons (mask_length);
635 memcpy (&qe->msg->key, key, sizeof (struct GNUNET_HashCode));
636 qe->cont_datum = cont;
637 qe->cont_cls = cont_cls;
638 qe->was_transmitted = GNUNET_NO;
639 qe->timeout_task = GNUNET_SCHEDULER_add_delayed (timeout, &timeout_queue_entry, qe);
640 qe->response_proc = &process_result_message;
641 qe->timeout = GNUNET_TIME_relative_to_absolute (timeout);
642
643 vector = (int32_t*) & qe->msg[1];
644 // copy each element over to the message
645 for (i = 0; i < element_count; i++)
646 vector[i] = htonl (elements[i]);
647
648 // fill in the mask
649 memcpy (&vector[element_count], mask, mask_length);
650
651 process_queue (h);
652 return qe;
653}
654
655
656/**
657 * Connect to the vectorproduct service.
658 *
659 * @param cfg configuration to use
660 * @return handle to use to access the service
661 */
662struct GNUNET_VECTORPRODUCT_Handle *
663GNUNET_VECTORPRODUCT_connect (const struct GNUNET_CONFIGURATION_Handle * cfg)
664{
665 struct GNUNET_CLIENT_Connection *client;
666 struct GNUNET_VECTORPRODUCT_Handle *h;
667
668 client = GNUNET_CLIENT_connect ("vectorproduct", cfg);
669
670 if (NULL == client)
671 {
672 LOG (GNUNET_ERROR_TYPE_ERROR,
673 _ ("Failed to connect to the vectorproduct service\n"));
674 return NULL;
675 }
676
677 h = GNUNET_malloc (sizeof (struct GNUNET_VECTORPRODUCT_Handle) +
678 GNUNET_SERVER_MAX_MESSAGE_SIZE - 1);
679 h->client = client;
680 h->cfg = cfg;
681 h->stats = GNUNET_STATISTICS_create ("vectorproduct-api", cfg);
682 return h;
683}
684
685
686/**
687 * Disconnect from the vectorproduct service.
688 *
689 * @param h handle to the vectorproduct
690 */
691void
692GNUNET_VECTORPRODUCT_disconnect (struct GNUNET_VECTORPRODUCT_Handle * h)
693{
694 struct GNUNET_VECTORPRODUCT_QueueEntry * qe;
695
696 LOG (GNUNET_ERROR_TYPE_INFO,
697 "Disconnecting from VectorProduct\n");
698
699 while (NULL != h->queue_head)
700 {
701 GNUNET_assert (NULL != (qe = free_queue_head_entry (h)));
702 qe->response_proc (qe, NULL, GNUNET_VECTORPRODUCT_Status_ServiceDisconnected);
703 }
704
705 if (h->client != NULL)
706 {
707 GNUNET_CLIENT_disconnect (h->client);
708 h->client = NULL;
709 }
710
711 GNUNET_STATISTICS_destroy (h->stats, GNUNET_NO);
712 h->stats = NULL;
713}
714
715/* end of ext_api.c */
diff --git a/src/vectorproduct/vectorproduct_testing.h b/src/vectorproduct/vectorproduct_testing.h
new file mode 100644
index 000000000..19e4f6163
--- /dev/null
+++ b/src/vectorproduct/vectorproduct_testing.h
@@ -0,0 +1,129 @@
1/*
2 * File: vectorproduct_testing.h
3 * Author: gnunet
4 *
5 * Created on June 29, 2013, 7:39 PM
6 */
7
8#ifndef VECTORPRODUCT_TESTING_H
9#define VECTORPRODUCT_TESTING_H
10
11#ifdef __cplusplus
12extern "C" {
13#endif
14
15struct GNUNET_VECTORPRODUCT_TESTING_handle
16{
17 /**
18 * Testing library system handle
19 */
20 struct GNUNET_TESTING_System *tl_system;
21
22 /**
23 * head DLL of peers
24 */
25 struct PeerContext *p_head;
26
27 /**
28 * tail DLL of peers
29 */
30 struct PeerContext *p_tail;
31};
32
33struct PeerContext
34{
35 /**
36 * Next element in the DLL
37 */
38 struct PeerContext *next;
39
40 /**
41 * Previous element in the DLL
42 */
43 struct PeerContext *prev;
44
45 /**
46 * Peer's testing handle
47 */
48 struct GNUNET_TESTING_Peer *peer;
49
50 /**
51 * Peer identity
52 */
53 struct GNUNET_PeerIdentity id;
54
55 /**
56 * Handle for the peer's ARM process
57 */
58 struct GNUNET_OS_Process *arm_proc;
59
60 /**
61 * Pointer to Vector Product Handle
62 */
63 struct GNUNET_VECTORPRODUCT_Handle *vh;
64
65 /**
66 * Closure for the callbacks
67 */
68 void *cb_cls;
69
70 /**
71 * An unique number to identify the peer
72 */
73 unsigned int no;
74
75 /**
76 * Peer's configuration
77 */
78 struct GNUNET_CONFIGURATION_Handle *cfg;
79
80 /**
81 * Pointer to the master testing handle
82 */
83 struct GNUNET_VECTORPRODUCT_TESTING_handle * vth;
84
85 /**
86 * Callback when two peers are connected and both have called the connect callback
87 * to notify clients about a new peer
88 */
89 void (*start_cb) (struct PeerContext * p, void *cls);
90
91// /**
92// * Pointer to function where the test occurs
93// */
94// GNUNET_VECTORPRODUCT_TESTING_start_cb start_cb;
95};
96
97/**
98 * Callback when two peers are connected and both have called the connect callback
99 * to notify clients about a new peer
100 */
101typedef void (*GNUNET_VECTORPRODUCT_TESTING_start_cb) (struct PeerContext * p,
102 void *cls);
103
104struct GNUNET_VECTORPRODUCT_TESTING_handle *
105GNUNET_VECTORPRODUCT_TESTING_init();
106
107static void
108GNUNET_VECTORPRODUCT_TESTING_done(struct GNUNET_VECTORPRODUCT_TESTING_handle * vth);
109
110struct PeerContext *
111GNUNET_VECTORPRODUCT_TESTING_start_peer (struct GNUNET_VECTORPRODUCT_TESTING_handle * vth,
112 const char *cfgname, int peer_id,
113 GNUNET_VECTORPRODUCT_TESTING_start_cb start_cb,
114 void *cb_cls);
115
116static void
117GNUNET_VECTORPRODUCT_TESTING_stop_peer
118 (struct GNUNET_VECTORPRODUCT_TESTING_handle * vth,
119 struct PeerContext *p);
120
121
122
123
124#ifdef __cplusplus
125}
126#endif
127
128#endif /* VECTORPRODUCT_TESTING_H */
129