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