diff options
-rw-r--r-- | configure.ac | 10 | ||||
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/include/Makefile.am | 1 | ||||
-rw-r--r-- | src/include/gnunet_scalarproduct_service.h (renamed from src/include/gnunet_vectorproduct_service.h) | 0 | ||||
-rw-r--r-- | src/scalarproduct/Makefile.am | 112 | ||||
-rw-r--r-- | src/scalarproduct/gnunet-service-vectorproduct.c | 2067 | ||||
-rw-r--r-- | src/scalarproduct/gnunet-vectorproduct.c | 410 | ||||
-rw-r--r-- | src/scalarproduct/gnunet_vectorproduct.h | 274 | ||||
-rw-r--r-- | src/scalarproduct/test_vectorproduct_api.c | 865 | ||||
-rw-r--r-- | src/scalarproduct/test_vectorproduct_api_4peers.c | 1084 | ||||
-rw-r--r-- | src/scalarproduct/test_vectorproduct_api_data.conf | 96 | ||||
-rw-r--r-- | src/scalarproduct/test_vectorproduct_api_regression.c | 852 | ||||
-rw-r--r-- | src/scalarproduct/test_vectorproduct_api_regression2.c | 931 | ||||
-rw-r--r-- | src/scalarproduct/vectorproduct.conf | 7 | ||||
-rw-r--r-- | src/scalarproduct/vectorproduct.conf.in | 7 | ||||
-rw-r--r-- | src/scalarproduct/vectorproduct_api.c | 715 | ||||
-rw-r--r-- | src/scalarproduct/vectorproduct_testing.h | 129 |
17 files changed, 7557 insertions, 7 deletions
diff --git a/configure.ac b/configure.ac index 321032e37..ecb282159 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -1291,10 +1291,11 @@ src/gns/Makefile | |||
1291 | src/gns/gns.conf | 1291 | src/gns/gns.conf |
1292 | src/gns/nss/Makefile | 1292 | src/gns/nss/Makefile |
1293 | src/hello/Makefile | 1293 | src/hello/Makefile |
1294 | src/include/Makefile | ||
1295 | src/include/gnunet_directories.h | ||
1296 | src/identity/Makefile | 1294 | src/identity/Makefile |
1297 | src/identity/identity.conf | 1295 | src/identity/identity.conf |
1296 | src/include/Makefile | ||
1297 | src/include/gnunet_directories.h | ||
1298 | src/integration-tests/Makefile | ||
1298 | src/hostlist/Makefile | 1299 | src/hostlist/Makefile |
1299 | src/lockmanager/Makefile | 1300 | src/lockmanager/Makefile |
1300 | src/lockmanager/lockmanager.conf | 1301 | src/lockmanager/lockmanager.conf |
@@ -1313,6 +1314,8 @@ src/postgres/Makefile | |||
1313 | src/pt/Makefile | 1314 | src/pt/Makefile |
1314 | src/regex/Makefile | 1315 | src/regex/Makefile |
1315 | src/regex/regex.conf | 1316 | src/regex/regex.conf |
1317 | src/scalarproduct/Makefile | ||
1318 | src/scalarproduct/vectorproduct.conf | ||
1316 | src/set/Makefile | 1319 | src/set/Makefile |
1317 | src/set/set.conf | 1320 | src/set/set.conf |
1318 | src/statistics/Makefile | 1321 | src/statistics/Makefile |
@@ -1329,9 +1332,6 @@ src/util/Makefile | |||
1329 | src/util/resolver.conf | 1332 | src/util/resolver.conf |
1330 | src/vpn/Makefile | 1333 | src/vpn/Makefile |
1331 | src/vpn/vpn.conf | 1334 | src/vpn/vpn.conf |
1332 | src/vectorproduct/Makefile | ||
1333 | src/vectorproduct/vectorproduct.conf | ||
1334 | src/integration-tests/Makefile | ||
1335 | pkgconfig/Makefile | 1335 | pkgconfig/Makefile |
1336 | pkgconfig/gnunetats.pc | 1336 | pkgconfig/gnunetats.pc |
1337 | pkgconfig/gnunetarm.pc | 1337 | pkgconfig/gnunetarm.pc |
diff --git a/src/Makefile.am b/src/Makefile.am index 524098992..fcc18d3ea 100644 --- a/src/Makefile.am +++ b/src/Makefile.am | |||
@@ -7,12 +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 | 10 | SCALARPRODUCT = scalarproduct |
11 | endif | 11 | endif |
12 | 12 | ||
13 | if HAVE_EXPERIMENTAL | 13 | if HAVE_EXPERIMENTAL |
14 | 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 | 15 | #note: scalarproduct is not being listed here yet as the crypto is being reworked at the moment |
16 | endif | 16 | endif |
17 | 17 | ||
18 | if HAVE_MYSQL | 18 | if HAVE_MYSQL |
diff --git a/src/include/Makefile.am b/src/include/Makefile.am index ee0ccc043..f93c60bdf 100644 --- a/src/include/Makefile.am +++ b/src/include/Makefile.am | |||
@@ -70,6 +70,7 @@ gnunetinclude_HEADERS = \ | |||
70 | gnunet_protocols.h \ | 70 | gnunet_protocols.h \ |
71 | gnunet_resolver_service.h \ | 71 | gnunet_resolver_service.h \ |
72 | gnunet_regex_service.h \ | 72 | gnunet_regex_service.h \ |
73 | gnunet_scalarproduct_service.h \ | ||
73 | gnunet_scheduler_lib.h \ | 74 | gnunet_scheduler_lib.h \ |
74 | gnunet_server_lib.h \ | 75 | gnunet_server_lib.h \ |
75 | gnunet_service_lib.h \ | 76 | gnunet_service_lib.h \ |
diff --git a/src/include/gnunet_vectorproduct_service.h b/src/include/gnunet_scalarproduct_service.h index 743a7365d..743a7365d 100644 --- a/src/include/gnunet_vectorproduct_service.h +++ b/src/include/gnunet_scalarproduct_service.h | |||
diff --git a/src/scalarproduct/Makefile.am b/src/scalarproduct/Makefile.am new file mode 100644 index 000000000..1f0912e50 --- /dev/null +++ b/src/scalarproduct/Makefile.am | |||
@@ -0,0 +1,112 @@ | |||
1 | INCLUDES = -I$(top_srcdir)/src/include | ||
2 | |||
3 | pkgcfgdir= $(pkgdatadir)/config.d/ | ||
4 | |||
5 | libexecdir= $(pkglibdir)/libexec/ | ||
6 | |||
7 | pkgcfg_DATA = \ | ||
8 | vectorproduct.conf | ||
9 | |||
10 | if MINGW | ||
11 | WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols | ||
12 | endif | ||
13 | |||
14 | if USE_COVERAGE | ||
15 | AM_CFLAGS = -fprofile-arcs -ftest-coverage | ||
16 | endif | ||
17 | |||
18 | bin_PROGRAMS = \ | ||
19 | gnunet-vectorproduct | ||
20 | |||
21 | libexec_PROGRAMS = \ | ||
22 | gnunet-service-vectorproduct | ||
23 | |||
24 | # FIXME: add option "configure --with-evil"? | ||
25 | #if HAVE_EXPERIMENTAL | ||
26 | #libexec_PROGRAMS += \ | ||
27 | # gnunet-service-evil-consensus | ||
28 | #endif | ||
29 | |||
30 | lib_LTLIBRARIES = \ | ||
31 | libgnunetvectorproduct.la | ||
32 | |||
33 | gnunet_vectorproduct_SOURCES = \ | ||
34 | gnunet-vectorproduct.c | ||
35 | gnunet_vectorproduct_LDADD = \ | ||
36 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
37 | $(top_builddir)/src/vectorproduct/libgnunetvectorproduct.la \ | ||
38 | -lgcrypt \ | ||
39 | $(GN_LIBINTL) | ||
40 | gnunet_vectorproduct_DEPENDENCIES = \ | ||
41 | libgnunetvectorproduct.la | ||
42 | |||
43 | gnunet_service_vectorproduct_SOURCES = \ | ||
44 | gnunet-service-vectorproduct.c | ||
45 | gnunet_service_vectorproduct_LDADD = \ | ||
46 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
47 | $(top_builddir)/src/core/libgnunetcore.la \ | ||
48 | $(top_builddir)/src/mesh/libgnunetmesh.la \ | ||
49 | $(top_builddir)/src/set/libgnunetset.la \ | ||
50 | -lgcrypt \ | ||
51 | $(GN_LIBINTL) | ||
52 | |||
53 | libgnunetvectorproduct_la_SOURCES = \ | ||
54 | vectorproduct_api.c | ||
55 | libgnunetvectorproduct_la_LIBADD = \ | ||
56 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
57 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
58 | -lgcrypt \ | ||
59 | $(LTLIBINTL) | ||
60 | libgnunetvectorproduct_la_LDFLAGS = \ | ||
61 | $(GN_LIB_LDFLAGS) | ||
62 | |||
63 | check_PROGRAMS = \ | ||
64 | test_vectorproduct_api_regression \ | ||
65 | test_vectorproduct_api \ | ||
66 | test_vectorproduct_api_4peers | ||
67 | #FIXME unfinished | ||
68 | #test_vectorproduct_api_regression2 | ||
69 | |||
70 | if ENABLE_TEST_RUN | ||
71 | TESTS = $(check_PROGRAMS) | ||
72 | endif | ||
73 | |||
74 | test_consensus_api_SOURCES = \ | ||
75 | test_consensus_api.c | ||
76 | test_consensus_api_LDADD = \ | ||
77 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
78 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
79 | $(top_builddir)/src/consensus/libgnunetconsensus.la | ||
80 | |||
81 | test_vectorproduct_api_SOURCES = \ | ||
82 | test_vectorproduct_api.c | ||
83 | test_vectorproduct_api_LDADD = \ | ||
84 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
85 | $(top_builddir)/src/vectorproduct/libgnunetvectorproduct.la \ | ||
86 | -lgcrypt | ||
87 | |||
88 | #FIXME unfinished | ||
89 | #test_vectorproduct_api_regression2_SOURCES = \ | ||
90 | # test_vectorproduct_api_regression2.c | ||
91 | #test_vectorproduct_api_regression2_LDADD = \ | ||
92 | # $(top_builddir)/src/vectorproduct/libgnunetvectorproduct.la \ | ||
93 | # $(top_builddir)/src/util/libgnunetutil.la \ | ||
94 | # -lgcrypt | ||
95 | |||
96 | test_vectorproduct_api_regression_SOURCES = \ | ||
97 | test_vectorproduct_api_regression.c | ||
98 | test_vectorproduct_api_regression_LDADD = \ | ||
99 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
100 | $(top_builddir)/src/vectorproduct/libgnunetvectorproduct.la \ | ||
101 | -lgcrypt | ||
102 | |||
103 | test_vectorproduct_api_4peers_SOURCES = \ | ||
104 | test_vectorproduct_api_4peers.c | ||
105 | test_vectorproduct_api_4peers_LDADD = \ | ||
106 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
107 | $(top_builddir)/src/vectorproduct/libgnunetvectorproduct.la \ | ||
108 | -lgcrypt | ||
109 | |||
110 | EXTRA_DIST = \ | ||
111 | test_vectorproduct.conf | ||
112 | |||
diff --git a/src/scalarproduct/gnunet-service-vectorproduct.c b/src/scalarproduct/gnunet-service-vectorproduct.c new file mode 100644 index 000000000..8724af60d --- /dev/null +++ b/src/scalarproduct/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 | */ | ||
43 | static struct GNUNET_CORE_Handle *my_core; | ||
44 | |||
45 | /** | ||
46 | * Handle to the core service (NULL until we've connected to it). | ||
47 | */ | ||
48 | static struct GNUNET_MESH_Handle *my_mesh; | ||
49 | |||
50 | /** | ||
51 | * The identity of this host. | ||
52 | */ | ||
53 | static struct GNUNET_PeerIdentity me; | ||
54 | |||
55 | /** | ||
56 | * Service's own public key represented as string | ||
57 | */ | ||
58 | static unsigned char * my_pubkey_external; | ||
59 | |||
60 | /** | ||
61 | * Service's own public key represented as string | ||
62 | */ | ||
63 | static uint16_t my_pubkey_external_length = 0; | ||
64 | |||
65 | /** | ||
66 | * Service's own n | ||
67 | */ | ||
68 | static gcry_mpi_t my_n; | ||
69 | |||
70 | /** | ||
71 | * Service's own n^2 (kept for performance) | ||
72 | */ | ||
73 | static gcry_mpi_t my_nsquare; | ||
74 | |||
75 | /** | ||
76 | * Service's own public exponent | ||
77 | */ | ||
78 | static gcry_mpi_t my_g; | ||
79 | |||
80 | /** | ||
81 | * Service's own private multiplier | ||
82 | */ | ||
83 | static gcry_mpi_t my_mu; | ||
84 | |||
85 | /** | ||
86 | * Service's own private exponent | ||
87 | */ | ||
88 | static 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 | */ | ||
95 | static 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 | */ | ||
101 | static 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 | */ | ||
108 | static 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 | */ | ||
115 | static struct ServiceSession * from_service_tail; | ||
116 | |||
117 | /** | ||
118 | * Certain events (callbacks for server & mesh operations) must not be queued after shutdown. | ||
119 | */ | ||
120 | static 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 | */ | ||
129 | static void | ||
130 | generate_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 | */ | ||
246 | static void | ||
247 | adjust (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 | */ | ||
267 | static void | ||
268 | encrypt_element (gcry_mpi_t c, gcry_mpi_t m, gcry_mpi_t g, gcry_mpi_t r, gcry_mpi_t n, gcry_mpi_t n_square) | ||
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 | */ | ||
311 | static void | ||
312 | decrypt_element (gcry_mpi_t m, gcry_mpi_t c, gcry_mpi_t mu, gcry_mpi_t lambda, gcry_mpi_t n, gcry_mpi_t n_square) | ||
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 | */ | ||
332 | static gcry_mpi_t | ||
333 | compute_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 | */ | ||
364 | static size_t | ||
365 | do_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 | */ | ||
399 | static gcry_mpi_t * | ||
400 | initialize_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 | */ | ||
419 | static gcry_mpi_t * | ||
420 | permute_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 | */ | ||
446 | static gcry_mpi_t * | ||
447 | generate_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 | */ | ||
480 | static struct ServiceSession * | ||
481 | find_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 | |||
511 | static void | ||
512 | destroy_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 | |||
527 | static void | ||
528 | free_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 | */ | ||
567 | static void | ||
568 | handle_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 | */ | ||
608 | static void | ||
609 | prepare_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)}) times 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)}) times 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)}) times 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)}) times 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 | */ | ||
674 | static int | ||
675 | prepare_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)}) times 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)}) times 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 | */ | ||
815 | static int | ||
816 | compute_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 | |||
1006 | except: | ||
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 | */ | ||
1029 | static void | ||
1030 | prepare_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 | */ | ||
1168 | static void | ||
1169 | tunnel_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 | */ | ||
1205 | static void | ||
1206 | handle_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 | */ | ||
1371 | static void * | ||
1372 | tunnel_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 | */ | ||
1395 | static void | ||
1396 | tunnel_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)}) times 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)}) times 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 | */ | ||
1451 | static gcry_mpi_t | ||
1452 | compute_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 | */ | ||
1535 | static void | ||
1536 | prepare_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 | */ | ||
1607 | static int | ||
1608 | handle_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 | ¤t[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 | } | ||
1768 | except: | ||
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 | */ | ||
1802 | static int | ||
1803 | handle_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 | |||
1906 | invalid_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 | */ | ||
1937 | static void | ||
1938 | shutdown_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 | */ | ||
1978 | static void | ||
1979 | core_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 | */ | ||
1994 | static void | ||
1995 | run (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 | */ | ||
2057 | int | ||
2058 | main (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/scalarproduct/gnunet-vectorproduct.c b/src/scalarproduct/gnunet-vectorproduct.c new file mode 100644 index 000000000..449085593 --- /dev/null +++ b/src/scalarproduct/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 | */ | ||
39 | static char *input_peer_id = NULL; | ||
40 | |||
41 | /** | ||
42 | * Option -p: destination peer identity for checking message-ids with | ||
43 | */ | ||
44 | static char *input_key = NULL; | ||
45 | |||
46 | /** | ||
47 | * Option -e: vector to calculate a vectorproduct with | ||
48 | */ | ||
49 | static char *input_elements = NULL; | ||
50 | |||
51 | /** | ||
52 | * Option -m: message-ids to calculate a vectorproduct with | ||
53 | */ | ||
54 | static char *input_mask = NULL; | ||
55 | |||
56 | /** | ||
57 | * the count of the messages sent to the service for processing | ||
58 | */ | ||
59 | static unsigned short element_count; | ||
60 | |||
61 | /** | ||
62 | * the count of the mask bytes | ||
63 | */ | ||
64 | unsigned short mask_length = 0; | ||
65 | |||
66 | /** | ||
67 | * the count of the number of mask bytes | ||
68 | */ | ||
69 | unsigned short mask_bytes; | ||
70 | |||
71 | /** | ||
72 | * the array of converted message IDs to send to our service | ||
73 | */ | ||
74 | static int32_t * elements = NULL; | ||
75 | |||
76 | /** | ||
77 | * the array of converted message IDs to send to our service | ||
78 | */ | ||
79 | static unsigned char * mask = NULL; | ||
80 | |||
81 | /** | ||
82 | * information about the peer we are comparing with | ||
83 | */ | ||
84 | struct GNUNET_PeerIdentity peer; | ||
85 | |||
86 | /** | ||
87 | * information about the peer we are comparing with | ||
88 | */ | ||
89 | struct GNUNET_HashCode key; | ||
90 | |||
91 | /** | ||
92 | * Pointer to the GNUNET_VECTORPRODUCT_Handle | ||
93 | */ | ||
94 | struct GNUNET_VECTORPRODUCT_Handle *handle; | ||
95 | |||
96 | /** | ||
97 | * Global return value | ||
98 | */ | ||
99 | static int ret; | ||
100 | |||
101 | struct GNUNET_VECTORPRODUCT_TestCls | ||
102 | { | ||
103 | struct GNUNET_VECTORPRODUCT_Handle * h; | ||
104 | }; | ||
105 | |||
106 | struct 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 | */ | ||
115 | static void | ||
116 | responder_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 | */ | ||
159 | static void | ||
160 | requester_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 | */ | ||
224 | static void | ||
225 | run (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 | */ | ||
384 | int | ||
385 | main (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/scalarproduct/gnunet_vectorproduct.h b/src/scalarproduct/gnunet_vectorproduct.h new file mode 100644 index 000000000..4b116646b --- /dev/null +++ b/src/scalarproduct/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 | ||
48 | extern "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 | */ | ||
60 | struct 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 | */ | ||
100 | struct 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 | */ | ||
133 | enum 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 | */ | ||
145 | enum 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 | */ | ||
157 | struct 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 | */ | ||
256 | struct 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/scalarproduct/test_vectorproduct_api.c b/src/scalarproduct/test_vectorproduct_api.c new file mode 100644 index 000000000..802015694 --- /dev/null +++ b/src/scalarproduct/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 | */ | ||
53 | struct 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 | */ | ||
79 | enum 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 | */ | ||
110 | static unsigned int max_mids; | ||
111 | |||
112 | /** | ||
113 | * Session Key used by both the test peers | ||
114 | */ | ||
115 | char input_key[103] = "helloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhe"; | ||
116 | |||
117 | /** | ||
118 | * Input elements for peer1 | ||
119 | */ | ||
120 | 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"; | ||
121 | //char input_elements_peer1[] = "11,11,11"; | ||
122 | |||
123 | /** | ||
124 | * Input Mask for peer 1 | ||
125 | */ | ||
126 | 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"; | ||
127 | //char input_mask_peer1[] = "1,1,1"; | ||
128 | |||
129 | /** | ||
130 | * the array of converted message IDs to send to our service | ||
131 | */ | ||
132 | static int32_t * elements_peer1 = NULL; | ||
133 | |||
134 | /** | ||
135 | * Number of elements | ||
136 | */ | ||
137 | uint16_t element_count_peer1 = 0; | ||
138 | |||
139 | /** | ||
140 | * Input elements for peer2 | ||
141 | */ | ||
142 | 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"; | ||
143 | //char input_elements_peer2[] = "11,11,11"; | ||
144 | |||
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"; | ||
149 | //char input_mask_peer2[] = "1,1,1"; | ||
150 | |||
151 | /** | ||
152 | * the array of converted message IDs to send to our service | ||
153 | */ | ||
154 | static int32_t * elements_peer2 = NULL; | ||
155 | |||
156 | /** | ||
157 | * the array of converted message IDs to send to our service | ||
158 | */ | ||
159 | static unsigned char * mask_peer2 = NULL; | ||
160 | |||
161 | /** | ||
162 | * Number of elements | ||
163 | */ | ||
164 | uint16_t element_count_peer2 = 0; | ||
165 | |||
166 | /** | ||
167 | * Data context for peer 1 | ||
168 | */ | ||
169 | static struct PeerData peer1; | ||
170 | |||
171 | /** | ||
172 | * Data context for peer 2 | ||
173 | */ | ||
174 | static struct PeerData peer2; | ||
175 | |||
176 | /** | ||
177 | * Various states during test setup | ||
178 | */ | ||
179 | static enum SetupState setup_state; | ||
180 | |||
181 | /** | ||
182 | * Testbed operation handle | ||
183 | */ | ||
184 | static struct GNUNET_TESTBED_Operation *op; | ||
185 | |||
186 | static int ok; | ||
187 | |||
188 | static int responder_ok; | ||
189 | |||
190 | static int requester_ok; | ||
191 | |||
192 | static GNUNET_SCHEDULER_TaskIdentifier abort_task; | ||
193 | /****************************************************************************** | ||
194 | *** Static Functions ***************************** | ||
195 | ******************************************************************************/ | ||
196 | |||
197 | static void | ||
198 | do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
199 | |||
200 | |||
201 | /** | ||
202 | * Close sockets and stop testing deamons nicely | ||
203 | */ | ||
204 | static void | ||
205 | do_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 | */ | ||
226 | static void | ||
227 | do_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 | */ | ||
254 | static void | ||
255 | do_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 | */ | ||
270 | static void | ||
271 | controller_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 | |||
288 | static void | ||
289 | responder_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 | |||
331 | static void | ||
332 | requester_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 | */ | ||
459 | static struct GNUNET_VECTORPRODUCT_QueueEntry * | ||
460 | requester_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 | */ | ||
577 | static struct GNUNET_VECTORPRODUCT_QueueEntry * | ||
578 | responder_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 | */ | ||
645 | static void | ||
646 | request_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 | */ | ||
660 | static void | ||
661 | prepare_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 | */ | ||
679 | static void | ||
680 | vectorproduct_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 | */ | ||
699 | static void * | ||
700 | vectorproduct_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 | */ | ||
749 | static void | ||
750 | peerinfo_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 | */ | ||
803 | static void | ||
804 | test_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 | */ | ||
829 | int | ||
830 | main (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/scalarproduct/test_vectorproduct_api_4peers.c b/src/scalarproduct/test_vectorproduct_api_4peers.c new file mode 100644 index 000000000..73ab634f9 --- /dev/null +++ b/src/scalarproduct/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 | */ | ||
71 | struct 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 | */ | ||
129 | enum 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 | */ | ||
180 | static unsigned int max_mids; | ||
181 | |||
182 | /** | ||
183 | * Session Key used by both the test peers | ||
184 | */ | ||
185 | char input_key_p1_p3[103] = "111111111111111111111111111111111111111111111111113333333333333333333333333333333333333333333333333333"; | ||
186 | |||
187 | /** | ||
188 | * Session Key used by both the test peers | ||
189 | */ | ||
190 | char input_key_p1_p4[103] = "111111111111111111111111111111111111111111111111114444444444444444444444444444444444444444444444444444"; | ||
191 | |||
192 | /** | ||
193 | * Session Key used by both the test peers | ||
194 | */ | ||
195 | char input_key_p2_p3[103] = "222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333"; | ||
196 | |||
197 | /** | ||
198 | * Session Key used by both the test peers | ||
199 | */ | ||
200 | char 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"; | ||
206 | char 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"; | ||
212 | char 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"; | ||
218 | char 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"; | ||
223 | char 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"; | ||
229 | char 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"; | ||
235 | char 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"; | ||
241 | char 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"; | ||
246 | char input_mask_peer4[] = "1,1,1"; | ||
247 | |||
248 | |||
249 | /** | ||
250 | * Data context for peer 1 | ||
251 | */ | ||
252 | static struct PeerData peer1; | ||
253 | |||
254 | /** | ||
255 | * Data context for peer 2 | ||
256 | */ | ||
257 | static struct PeerData peer2; | ||
258 | |||
259 | /** | ||
260 | * Data context for peer 3 | ||
261 | */ | ||
262 | static struct PeerData peer3; | ||
263 | |||
264 | /** | ||
265 | * Data context for peer 4 | ||
266 | */ | ||
267 | static struct PeerData peer4; | ||
268 | |||
269 | /** | ||
270 | * Various states during test setup | ||
271 | */ | ||
272 | static enum SetupState setup_state; | ||
273 | |||
274 | /** | ||
275 | * Testbed operation handle | ||
276 | */ | ||
277 | static struct GNUNET_TESTBED_Operation *op; | ||
278 | |||
279 | /** | ||
280 | * Return value for the test | ||
281 | */ | ||
282 | static int ok; | ||
283 | |||
284 | /** | ||
285 | * Abort Task for timeout | ||
286 | */ | ||
287 | static GNUNET_SCHEDULER_TaskIdentifier abort_task; | ||
288 | /****************************************************************************** | ||
289 | *** Static Functions ***************************** | ||
290 | ******************************************************************************/ | ||
291 | |||
292 | static void | ||
293 | do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
294 | |||
295 | |||
296 | /** | ||
297 | * Close sockets and stop testing deamons nicely | ||
298 | */ | ||
299 | static void | ||
300 | do_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 | |||
321 | static void | ||
322 | do_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 | */ | ||
350 | static void | ||
351 | do_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 | */ | ||
366 | static void | ||
367 | controller_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 | |||
389 | static void | ||
390 | responder_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 | |||
447 | static void | ||
448 | requester_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 | |||
532 | static struct GNUNET_VECTORPRODUCT_QueueEntry * | ||
533 | requester_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 | */ | ||
661 | static struct GNUNET_VECTORPRODUCT_QueueEntry * | ||
662 | responder_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 | |||
780 | static void | ||
781 | request_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 | |||
793 | static void | ||
794 | prepare_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 | */ | ||
815 | static void | ||
816 | vectorproduct_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 | */ | ||
837 | static void * | ||
838 | vectorproduct_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 | */ | ||
919 | static void | ||
920 | peerinfo_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 | */ | ||
1005 | static void | ||
1006 | test_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 | */ | ||
1066 | int | ||
1067 | main (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/scalarproduct/test_vectorproduct_api_data.conf b/src/scalarproduct/test_vectorproduct_api_data.conf new file mode 100644 index 000000000..b0b1c257e --- /dev/null +++ b/src/scalarproduct/test_vectorproduct_api_data.conf | |||
@@ -0,0 +1,96 @@ | |||
1 | [arm] | ||
2 | DEFAULTSERVICES = core transport vectorproduct mesh testbed | ||
3 | PORT = 12366 | ||
4 | |||
5 | [core] | ||
6 | PORT = 12092 | ||
7 | |||
8 | [vectorproduct] | ||
9 | #AUTOSTART = YES | ||
10 | BINARY = gnunet-service-vectorproduct | ||
11 | UNIXPATH = /tmp/gnunet-service-vectorproduct.sock | ||
12 | HOME = $SERVICEHOME | ||
13 | HOSTNAME = localhost | ||
14 | PORT = 2087 | ||
15 | |||
16 | [testbed] | ||
17 | OVERLAY_TOPOLOGY = CLIQUE | ||
18 | |||
19 | [lockmanager] | ||
20 | AUTOSTART = NO | ||
21 | ACCEPT_FROM = 127.0.0.1; | ||
22 | HOSTNAME = localhost | ||
23 | PORT = 12101 | ||
24 | |||
25 | [statistics] | ||
26 | AUTOSTART = YES | ||
27 | ACCEPT_FROM = 127.0.0.1; | ||
28 | PORT = 12102 | ||
29 | |||
30 | [fs] | ||
31 | AUTOSTART = NO | ||
32 | |||
33 | [resolver] | ||
34 | AUTOSTART = NO | ||
35 | |||
36 | [mesh] | ||
37 | # AUTOSTART = YES | ||
38 | ACCEPT_FROM = 127.0.0.1; | ||
39 | HOSTNAME = localhost | ||
40 | PORT = 10700 | ||
41 | # PREFIX = valgrind --leak-check=full | ||
42 | # PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args | ||
43 | |||
44 | [dht] | ||
45 | AUTOSTART = YES | ||
46 | ACCEPT_FROM6 = ::1; | ||
47 | ACCEPT_FROM = 127.0.0.1; | ||
48 | HOSTNAME = localhost | ||
49 | PORT = 12100 | ||
50 | |||
51 | [block] | ||
52 | plugins = dht test | ||
53 | |||
54 | [dhtcache] | ||
55 | QUOTA = 1 MB | ||
56 | DATABASE = sqlite | ||
57 | |||
58 | [transport] | ||
59 | PLUGINS = tcp | ||
60 | ACCEPT_FROM6 = ::1; | ||
61 | ACCEPT_FROM = 127.0.0.1; | ||
62 | NEIGHBOUR_LIMIT = 50 | ||
63 | PORT = 12365 | ||
64 | |||
65 | [ats] | ||
66 | WAN_QUOTA_OUT = 3932160 | ||
67 | WAN_QUOTA_IN = 3932160 | ||
68 | |||
69 | [transport-tcp] | ||
70 | TIMEOUT = 300 s | ||
71 | PORT = 12368 | ||
72 | |||
73 | [TESTING] | ||
74 | WEAKRANDOM = YES | ||
75 | |||
76 | [gnunetd] | ||
77 | HOSTKEY = $SERVICEHOME/.hostkey | ||
78 | |||
79 | [PATHS] | ||
80 | SERVICEHOME = /tmp/test-vectorproduct/ | ||
81 | |||
82 | [dns] | ||
83 | AUTOSTART = NO | ||
84 | |||
85 | [nse] | ||
86 | AUTOSTART = NO | ||
87 | |||
88 | [vpn] | ||
89 | AUTOSTART = NO | ||
90 | |||
91 | [nat] | ||
92 | RETURN_LOCAL_ADDRESSES = YES | ||
93 | |||
94 | [consensus] | ||
95 | AUTOSTART = NO | ||
96 | |||
diff --git a/src/scalarproduct/test_vectorproduct_api_regression.c b/src/scalarproduct/test_vectorproduct_api_regression.c new file mode 100644 index 000000000..2bc0adec6 --- /dev/null +++ b/src/scalarproduct/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 | */ | ||
59 | struct 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 | */ | ||
85 | enum 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 | */ | ||
116 | static unsigned int max_mids; | ||
117 | |||
118 | /** | ||
119 | * Session Key used by both the test peers | ||
120 | */ | ||
121 | char 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"; | ||
127 | char 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"; | ||
133 | char input_mask_peer1[] = "1,1,1"; | ||
134 | |||
135 | /** | ||
136 | * the array of converted message IDs to send to our service | ||
137 | */ | ||
138 | static 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"; | ||
144 | char 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"; | ||
149 | char input_mask_peer2[] = "1,1,1"; | ||
150 | /** | ||
151 | * the array of converted message IDs to send to our service | ||
152 | */ | ||
153 | static int32_t * elements_peer2 = NULL; | ||
154 | |||
155 | /** | ||
156 | * the array of converted message IDs to send to our service | ||
157 | */ | ||
158 | static unsigned char * mask_peer2 = NULL; | ||
159 | |||
160 | /** | ||
161 | * Data context for peer 1 | ||
162 | */ | ||
163 | static struct PeerData peer1; | ||
164 | |||
165 | /** | ||
166 | * Data context for peer 2 | ||
167 | */ | ||
168 | static struct PeerData peer2; | ||
169 | |||
170 | /** | ||
171 | * Various states during test setup | ||
172 | */ | ||
173 | static enum SetupState setup_state; | ||
174 | |||
175 | /** | ||
176 | * Testbed operation handle | ||
177 | */ | ||
178 | static struct GNUNET_TESTBED_Operation *op; | ||
179 | |||
180 | /** | ||
181 | * Return value of the test. | ||
182 | */ | ||
183 | static int ok; | ||
184 | |||
185 | /** | ||
186 | * Abort Task for timeout | ||
187 | */ | ||
188 | static 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 | */ | ||
199 | static void | ||
200 | do_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 | */ | ||
209 | static void | ||
210 | connect_peer (void *cls, | ||
211 | const struct GNUNET_SCHEDULER_TaskContext * tc); | ||
212 | |||
213 | |||
214 | /** | ||
215 | * Close sockets and stop testing deamons nicely | ||
216 | */ | ||
217 | static void | ||
218 | do_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 | */ | ||
240 | static void | ||
241 | do_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 | */ | ||
268 | static void | ||
269 | do_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 | */ | ||
284 | static void | ||
285 | controller_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 | */ | ||
314 | static void | ||
315 | responder_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 | */ | ||
368 | static void | ||
369 | requester_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 | |||
443 | static void | ||
444 | requester_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 | */ | ||
572 | static void | ||
573 | responder_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 | */ | ||
654 | static void | ||
655 | vectorproduct_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 | */ | ||
675 | static void * | ||
676 | vectorproduct_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 | */ | ||
729 | static void | ||
730 | connect_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 | */ | ||
751 | static void | ||
752 | peerinfo_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 | */ | ||
804 | static void | ||
805 | test_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 | */ | ||
830 | int | ||
831 | main (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/scalarproduct/test_vectorproduct_api_regression2.c b/src/scalarproduct/test_vectorproduct_api_regression2.c new file mode 100644 index 000000000..8a0162b40 --- /dev/null +++ b/src/scalarproduct/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 | */ | ||
45 | struct 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 | */ | ||
71 | enum 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 | */ | ||
102 | static unsigned int max_mids; | ||
103 | |||
104 | /** | ||
105 | * Session Key used by both the test peers | ||
106 | */ | ||
107 | char input_key[103] = "helloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhe"; | ||
108 | |||
109 | /** | ||
110 | * Input elements for peer1 | ||
111 | */ | ||
112 | 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"; | ||
113 | //char input_elements_peer1[] = "11,11,11"; | ||
114 | |||
115 | /** | ||
116 | * Input Mask for peer 1 | ||
117 | */ | ||
118 | 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"; | ||
119 | //char input_mask_peer1[] = "1,1,1"; | ||
120 | |||
121 | /** | ||
122 | * the array of converted message IDs to send to our service | ||
123 | */ | ||
124 | static int32_t * elements_peer1 = NULL; | ||
125 | |||
126 | /** | ||
127 | * the array of converted message IDs to send to our service | ||
128 | */ | ||
129 | static unsigned char * mask_peer1 = NULL; | ||
130 | |||
131 | /** | ||
132 | * Number of elements | ||
133 | */ | ||
134 | uint16_t element_count_peer1 = 0; | ||
135 | |||
136 | /** | ||
137 | * Input elements for peer2 | ||
138 | */ | ||
139 | 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"; | ||
140 | //char input_elements_peer2[] = "11,11,11"; | ||
141 | |||
142 | /** | ||
143 | * Input Mask for peer 2 | ||
144 | */ | ||
145 | 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"; | ||
146 | //char input_mask_peer2[] = "1,1,1"; | ||
147 | |||
148 | /** | ||
149 | * the array of converted message IDs to send to our service | ||
150 | */ | ||
151 | static int32_t * elements_peer2 = NULL; | ||
152 | |||
153 | /** | ||
154 | * the array of converted message IDs to send to our service | ||
155 | */ | ||
156 | static unsigned char * mask_peer2 = NULL; | ||
157 | |||
158 | /** | ||
159 | * Number of elements | ||
160 | */ | ||
161 | uint16_t element_count_peer2 = 0; | ||
162 | |||
163 | /** | ||
164 | * Data context for peer 1 | ||
165 | */ | ||
166 | static struct PeerData peer1; | ||
167 | |||
168 | /** | ||
169 | * Data context for peer 2 | ||
170 | */ | ||
171 | static struct PeerData peer2; | ||
172 | |||
173 | /** | ||
174 | * Various states during test setup | ||
175 | */ | ||
176 | static enum SetupState setup_state; | ||
177 | |||
178 | /** | ||
179 | * Testbed operation handle | ||
180 | */ | ||
181 | static struct GNUNET_TESTBED_Operation *op; | ||
182 | |||
183 | static int ok; | ||
184 | |||
185 | static int responder_ok; | ||
186 | |||
187 | static int requester_ok; | ||
188 | |||
189 | static GNUNET_SCHEDULER_TaskIdentifier abort_task; | ||
190 | /****************************************************************************** | ||
191 | *** Static Functions ***************************** | ||
192 | ******************************************************************************/ | ||
193 | |||
194 | static void | ||
195 | do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
196 | |||
197 | |||
198 | /** | ||
199 | * Close sockets and stop testing deamons nicely | ||
200 | */ | ||
201 | static void | ||
202 | do_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 | */ | ||
236 | static void | ||
237 | do_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 | */ | ||
264 | static void | ||
265 | do_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 | */ | ||
281 | static void | ||
282 | controller_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 | |||
304 | static void | ||
305 | responder_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 | |||
348 | static void | ||
349 | requester_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 | |||
478 | static struct GNUNET_VECTORPRODUCT_QueueEntry * | ||
479 | requester_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 | */ | ||
601 | static struct GNUNET_VECTORPRODUCT_QueueEntry * | ||
602 | responder_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 | */ | ||
675 | static void | ||
676 | request_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 | */ | ||
693 | static void | ||
694 | prepare_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 | |||
705 | static void | ||
706 | peer_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 | */ | ||
720 | static void | ||
721 | destroy_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 | */ | ||
739 | static void | ||
740 | vectorproduct_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 | */ | ||
759 | static void * | ||
760 | vectorproduct_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 | */ | ||
817 | static void | ||
818 | peerinfo_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 | */ | ||
872 | static void | ||
873 | test_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 | */ | ||
896 | int | ||
897 | main (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/scalarproduct/vectorproduct.conf b/src/scalarproduct/vectorproduct.conf new file mode 100644 index 000000000..d00093922 --- /dev/null +++ b/src/scalarproduct/vectorproduct.conf | |||
@@ -0,0 +1,7 @@ | |||
1 | [vectorproduct] | ||
2 | BINARY = gnunet-service-vectorproduct | ||
3 | UNIXPATH = /tmp/gnunet-service-vectorproduct.sock | ||
4 | HOME = $SERVICEHOME | ||
5 | # PORT = 2106 | ||
6 | # PORT = 2087 | ||
7 | |||
diff --git a/src/scalarproduct/vectorproduct.conf.in b/src/scalarproduct/vectorproduct.conf.in new file mode 100644 index 000000000..e47af6f6a --- /dev/null +++ b/src/scalarproduct/vectorproduct.conf.in | |||
@@ -0,0 +1,7 @@ | |||
1 | [vectorproduct] | ||
2 | BINARY = gnunet-service-vectorproduct | ||
3 | UNIXPATH = /tmp/gnunet-service-vectorproduct.sock | ||
4 | HOME = $SERVICEHOME | ||
5 | # PORT = 2106 | ||
6 | @UNIXONLY@ PORT = 2087 | ||
7 | |||
diff --git a/src/scalarproduct/vectorproduct_api.c b/src/scalarproduct/vectorproduct_api.c new file mode 100644 index 000000000..4f8cde8fe --- /dev/null +++ b/src/scalarproduct/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 | */ | ||
43 | struct 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 | */ | ||
124 | static struct GNUNET_VECTORPRODUCT_QueueEntry * | ||
125 | make_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 | */ | ||
132 | static struct GNUNET_VECTORPRODUCT_QueueEntry * | ||
133 | free_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 | */ | ||
141 | static void | ||
142 | timeout_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 | */ | ||
152 | static void | ||
153 | receive_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 | */ | ||
164 | static 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 | */ | ||
172 | static void | ||
173 | process_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 | */ | ||
187 | static struct GNUNET_VECTORPRODUCT_QueueEntry * | ||
188 | make_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 | */ | ||
218 | static struct GNUNET_VECTORPRODUCT_QueueEntry * | ||
219 | free_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 | */ | ||
255 | static void | ||
256 | timeout_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 | */ | ||
287 | static void | ||
288 | process_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 | */ | ||
308 | static void | ||
309 | process_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 | */ | ||
336 | static void | ||
337 | receive_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 | */ | ||
421 | static size_t | ||
422 | transmit_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 | */ | ||
482 | static void | ||
483 | process_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 | */ | ||
550 | struct GNUNET_VECTORPRODUCT_QueueEntry * | ||
551 | GNUNET_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 | */ | ||
606 | struct GNUNET_VECTORPRODUCT_QueueEntry * | ||
607 | GNUNET_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 | */ | ||
662 | struct GNUNET_VECTORPRODUCT_Handle * | ||
663 | GNUNET_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 | */ | ||
691 | void | ||
692 | GNUNET_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/scalarproduct/vectorproduct_testing.h b/src/scalarproduct/vectorproduct_testing.h new file mode 100644 index 000000000..19e4f6163 --- /dev/null +++ b/src/scalarproduct/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 | ||
12 | extern "C" { | ||
13 | #endif | ||
14 | |||
15 | struct 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 | |||
33 | struct 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 | */ | ||
101 | typedef void (*GNUNET_VECTORPRODUCT_TESTING_start_cb) (struct PeerContext * p, | ||
102 | void *cls); | ||
103 | |||
104 | struct GNUNET_VECTORPRODUCT_TESTING_handle * | ||
105 | GNUNET_VECTORPRODUCT_TESTING_init(); | ||
106 | |||
107 | static void | ||
108 | GNUNET_VECTORPRODUCT_TESTING_done(struct GNUNET_VECTORPRODUCT_TESTING_handle * vth); | ||
109 | |||
110 | struct PeerContext * | ||
111 | GNUNET_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 | |||
116 | static void | ||
117 | GNUNET_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 | |||