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