2 This file is part of GNUnet.
3 Copyright (C) 2013, 2014 Christian Grothoff (and other contributing authors)
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.
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.
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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
21 * @file scalarproduct/scalarproduct_api.c
22 * @brief API for the scalarproduct
23 * @author Christian Fuchs
24 * @author Gaurav Kukreja
25 * @author Christian Grothoff
30 #include "gnunet_util_lib.h"
31 #include "gnunet_statistics_service.h"
32 #include "gnunet_scalarproduct_service.h"
33 #include "gnunet_protocols.h"
34 #include "scalarproduct.h"
36 #define LOG(kind,...) GNUNET_log_from (kind, "scalarproduct-api",__VA_ARGS__)
40 * The abstraction function for our internal callback
42 * @param h computation handle
43 * @param msg response we got, NULL on errors
44 * @param status processing status code
47 (*GNUNET_SCALARPRODUCT_ResponseMessageHandler) (struct GNUNET_SCALARPRODUCT_ComputationHandle *h,
48 const struct ClientResponseMessage *msg,
49 enum GNUNET_SCALARPRODUCT_ResponseStatus status);
53 * A handle returned for each computation
55 struct GNUNET_SCALARPRODUCT_ComputationHandle
60 const struct GNUNET_CONFIGURATION_Handle *cfg;
63 * Current connection to the scalarproduct service.
65 struct GNUNET_CLIENT_Connection *client;
68 * Current transmit handle.
70 struct GNUNET_CLIENT_TransmitHandle *th;
73 * the client's elements which
75 struct GNUNET_SCALARPRODUCT_Element *elements;
78 * Message to be sent to the scalarproduct service
80 struct GNUNET_MessageHeader *msg;
83 * Function to call after transmission of the request (Bob).
85 GNUNET_SCALARPRODUCT_ContinuationWithStatus cont_status;
88 * Function to call after transmission of the request (Alice).
90 GNUNET_SCALARPRODUCT_DatumProcessor cont_datum;
93 * Closure for @e cont_status or @e cont_datum.
98 * API internal callback for results and failures to be forwarded to
101 GNUNET_SCALARPRODUCT_ResponseMessageHandler response_proc;
104 * The shared session key identifying this computation
106 struct GNUNET_HashCode key;
109 * count of all @e elements we offer for computation
111 uint32_t element_count_total;
114 * count of the transfered @e elements we offer for computation
116 uint32_t element_count_transfered;
119 * Type to use for the multipart messages.
127 * Called when a response is received from the service. After basic
128 * check, the handler in `h->response_proc` is called. This functions
129 * handles the response to the client which used the API.
131 * @param cls Pointer to the Master Context
132 * @param msg Pointer to the data received in response
135 receive_cb (void *cls,
136 const struct GNUNET_MessageHeader *msg)
138 struct GNUNET_SCALARPRODUCT_ComputationHandle *h = cls;
139 const struct ClientResponseMessage *message;
140 enum GNUNET_SCALARPRODUCT_ResponseStatus status;
144 LOG (GNUNET_ERROR_TYPE_INFO,
145 "Disconnected from SCALARPRODUCT service.\n");
148 GNUNET_SCALARPRODUCT_STATUS_DISCONNECTED);
151 if (ntohs (msg->size) < sizeof (struct ClientResponseMessage))
156 GNUNET_SCALARPRODUCT_STATUS_INVALID_RESPONSE);
159 message = (const struct ClientResponseMessage *) msg;
160 if (ntohs (msg->size) !=
161 ntohl (message->product_length) + sizeof (struct ClientResponseMessage))
166 GNUNET_SCALARPRODUCT_STATUS_INVALID_RESPONSE);
169 status = (enum GNUNET_SCALARPRODUCT_ResponseStatus) ntohl (message->status);
177 * Transmits the request to the SCALARPRODUCT service
179 * @param cls Closure with the `struct GNUNET_SCALARPRODUCT_ComputationHandle`
180 * @param size Size of the buffer @a buf
181 * @param buf Pointer to the buffer
182 * @return Size of the message sent
185 do_send_message (void *cls,
189 struct GNUNET_SCALARPRODUCT_ComputationHandle *h = cls;
190 struct ComputationBobCryptodataMultipartMessage *msg;
198 LOG (GNUNET_ERROR_TYPE_DEBUG,
199 "Failed to transmit request to SCALARPRODUCT.\n");
200 /* notify caller about the error, done here */
201 h->response_proc (h, NULL,
202 GNUNET_SCALARPRODUCT_STATUS_FAILURE);
205 ret = ntohs (h->msg->size);
206 memcpy (buf, h->msg, ret);
207 GNUNET_free (h->msg);
211 if (h->element_count_total == h->element_count_transfered)
213 GNUNET_CLIENT_receive (h->client,
215 GNUNET_TIME_UNIT_FOREVER_REL);
219 todo = h->element_count_total - h->element_count_transfered;
220 nsize = sizeof (struct ComputationBobCryptodataMultipartMessage)
221 + todo * sizeof (struct GNUNET_SCALARPRODUCT_Element);
222 if (GNUNET_SERVER_MAX_MESSAGE_SIZE <= size)
224 /* cannot do all of them, limit to what is possible in one message */
225 todo = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct ComputationBobCryptodataMultipartMessage))
226 / sizeof (struct GNUNET_SCALARPRODUCT_Element);
227 nsize = sizeof (struct ComputationBobCryptodataMultipartMessage)
228 + todo * sizeof (struct GNUNET_SCALARPRODUCT_Element);
231 msg = GNUNET_malloc (nsize);
232 h->msg = &msg->header;
233 msg->header.size = htons (nsize);
234 msg->header.type = htons (h->mp_type);
235 msg->element_count_contained = htonl (todo);
237 &h->elements[h->element_count_transfered],
238 todo * sizeof (struct GNUNET_SCALARPRODUCT_Element));
239 h->element_count_transfered += todo;
240 h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, nsize,
241 GNUNET_TIME_UNIT_FOREVER_REL,
243 &do_send_message, h);
244 GNUNET_assert (NULL != h->th);
250 * Handles the STATUS received from the service for a response, does
251 * not contain a payload. Called when we participate as "Bob" via
252 * #GNUNET_SCALARPRODUCT_accept_computation().
254 * @param h our Handle
255 * @param msg the response received
256 * @param status the condition the request was terminated with (eg: disconnect)
259 process_status_message (struct GNUNET_SCALARPRODUCT_ComputationHandle *h,
260 const struct ClientResponseMessage *msg,
261 enum GNUNET_SCALARPRODUCT_ResponseStatus status)
263 if (NULL != h->cont_status)
264 h->cont_status (h->cont_cls,
266 GNUNET_SCALARPRODUCT_cancel (h);
271 * Check if the keys for all given elements are unique.
273 * @param elements elements to check
274 * @param element_count size of the @a elements array
275 * @return #GNUNET_OK if all keys are unique
278 check_unique (const struct GNUNET_SCALARPRODUCT_Element *elements,
279 uint32_t element_count)
281 struct GNUNET_CONTAINER_MultiHashMap *map;
286 map = GNUNET_CONTAINER_multihashmap_create (2 * element_count,
288 for (i=0;i<element_count;i++)
290 GNUNET_CONTAINER_multihashmap_put (map,
293 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
295 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
296 _("Keys given to SCALARPRODUCT not unique!\n"));
299 GNUNET_CONTAINER_multihashmap_destroy (map);
305 * Used by Bob's client to cooperate with Alice,
307 * @param cfg the gnunet configuration handle
308 * @param key Session key unique to the requesting client
309 * @param elements Array of elements of the vector
310 * @param element_count Number of elements in the @a elements vector
311 * @param cont Callback function
312 * @param cont_cls Closure for @a cont
313 * @return a new handle for this computation
315 struct GNUNET_SCALARPRODUCT_ComputationHandle *
316 GNUNET_SCALARPRODUCT_accept_computation (const struct GNUNET_CONFIGURATION_Handle *cfg,
317 const struct GNUNET_HashCode *session_key,
318 const struct GNUNET_SCALARPRODUCT_Element *elements,
319 uint32_t element_count,
320 GNUNET_SCALARPRODUCT_ContinuationWithStatus cont,
323 struct GNUNET_SCALARPRODUCT_ComputationHandle *h;
324 struct BobComputationMessage *msg;
328 if (GNUNET_SYSERR == check_unique (elements, element_count))
330 h = GNUNET_new (struct GNUNET_SCALARPRODUCT_ComputationHandle);
331 h->cont_status = cont;
332 h->cont_cls = cont_cls;
333 h->response_proc = &process_status_message;
335 h->key = *session_key;
336 h->client = GNUNET_CLIENT_connect ("scalarproduct-bob", cfg);
337 h->element_count_total = element_count;
338 h->mp_type = GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART_BOB;
339 if (NULL == h->client)
341 /* scalarproduct configuration error */
346 size = sizeof (struct BobComputationMessage)
347 + element_count * sizeof (struct GNUNET_SCALARPRODUCT_Element);
348 if (GNUNET_SERVER_MAX_MESSAGE_SIZE > size)
350 possible = element_count;
351 h->element_count_transfered = element_count;
355 /* create a multipart msg, first we calculate a new msg size for the head msg */
356 possible = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct BobComputationMessage))
357 / sizeof (struct GNUNET_SCALARPRODUCT_Element);
358 h->element_count_transfered = possible;
359 size = sizeof (struct BobComputationMessage)
360 + possible * sizeof (struct GNUNET_SCALARPRODUCT_Element);
361 h->elements = GNUNET_malloc (sizeof(struct GNUNET_SCALARPRODUCT_Element) * element_count);
364 sizeof (struct GNUNET_SCALARPRODUCT_Element) * element_count);
367 msg = GNUNET_malloc (size);
368 h->msg = &msg->header;
369 msg->header.size = htons (size);
370 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB);
371 msg->element_count_total = htonl (element_count);
372 msg->element_count_contained = htonl (possible);
373 msg->session_key = *session_key;
376 possible * sizeof (struct GNUNET_SCALARPRODUCT_Element));
377 h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, size,
378 GNUNET_TIME_UNIT_FOREVER_REL,
379 GNUNET_YES, /* retry is OK in the initial stage */
380 &do_send_message, h);
381 GNUNET_assert (NULL != h->th);
387 * Handles the RESULT received from the service for a request, should
388 * contain a result MPI value. Called when we participate as "Alice" via
389 * #GNUNET_SCALARPRODUCT_start_computation().
391 * @param h our Handle
392 * @param msg Pointer to the response received
393 * @param status the condition the request was terminated with (eg: disconnect)
396 process_result_message (struct GNUNET_SCALARPRODUCT_ComputationHandle *h,
397 const struct ClientResponseMessage *msg,
398 enum GNUNET_SCALARPRODUCT_ResponseStatus status)
400 uint32_t product_len;
401 gcry_mpi_t result = NULL;
406 if (GNUNET_SCALARPRODUCT_STATUS_SUCCESS == status)
408 result = gcry_mpi_new (0);
410 product_len = ntohl (msg->product_length);
414 if (0 != (rc = gcry_mpi_scan (&num, GCRYMPI_FMT_STD,
419 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
422 gcry_mpi_release (result);
424 status = GNUNET_SCALARPRODUCT_STATUS_INVALID_RESPONSE;
428 if (0 < (int32_t) ntohl (msg->range))
429 gcry_mpi_add (result, result, num);
431 gcry_mpi_sub (result, result, num);
432 gcry_mpi_release (num);
436 if (NULL != h->cont_datum)
437 h->cont_datum (h->cont_cls,
441 gcry_mpi_release (result);
442 GNUNET_SCALARPRODUCT_cancel (h);
447 * Request by Alice's client for computing a scalar product
449 * @param cfg the gnunet configuration handle
450 * @param session_key Session key should be unique to the requesting client
451 * @param peer PeerID of the other peer
452 * @param elements Array of elements of the vector
453 * @param element_count Number of elements in the @a elements vector
454 * @param cont Callback function
455 * @param cont_cls Closure for @a cont
456 * @return a new handle for this computation
458 struct GNUNET_SCALARPRODUCT_ComputationHandle *
459 GNUNET_SCALARPRODUCT_start_computation (const struct GNUNET_CONFIGURATION_Handle *cfg,
460 const struct GNUNET_HashCode *session_key,
461 const struct GNUNET_PeerIdentity *peer,
462 const struct GNUNET_SCALARPRODUCT_Element *elements,
463 uint32_t element_count,
464 GNUNET_SCALARPRODUCT_DatumProcessor cont,
467 struct GNUNET_SCALARPRODUCT_ComputationHandle *h;
468 struct AliceComputationMessage *msg;
472 if (GNUNET_SYSERR == check_unique (elements, element_count))
474 h = GNUNET_new (struct GNUNET_SCALARPRODUCT_ComputationHandle);
475 h->client = GNUNET_CLIENT_connect ("scalarproduct-alice", cfg);
476 if (NULL == h->client)
478 /* missconfigured scalarproduct service */
483 h->element_count_total = element_count;
484 h->cont_datum = cont;
485 h->cont_cls = cont_cls;
486 h->response_proc = &process_result_message;
488 h->key = *session_key;
489 h->mp_type = GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART_ALICE;
490 size = sizeof (struct AliceComputationMessage)
491 + element_count * sizeof (struct GNUNET_SCALARPRODUCT_Element);
492 if (GNUNET_SERVER_MAX_MESSAGE_SIZE > size)
494 possible = element_count;
495 h->element_count_transfered = element_count;
499 /* create a multipart msg, first we calculate a new msg size for the head msg */
500 possible = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct AliceComputationMessage))
501 / sizeof (struct GNUNET_SCALARPRODUCT_Element);
502 h->element_count_transfered = possible;
503 size = sizeof (struct AliceComputationMessage)
504 + possible * sizeof (struct GNUNET_SCALARPRODUCT_Element);
505 h->elements = GNUNET_malloc (sizeof(struct GNUNET_SCALARPRODUCT_Element) * element_count);
508 sizeof (struct GNUNET_SCALARPRODUCT_Element) * element_count);
511 msg = GNUNET_malloc (size);
512 h->msg = &msg->header;
513 msg->header.size = htons (size);
514 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE);
515 msg->element_count_total = htonl (element_count);
516 msg->element_count_contained = htonl (possible);
517 msg->reserved = htonl (0);
519 msg->session_key = *session_key;
522 sizeof (struct GNUNET_SCALARPRODUCT_Element) * possible);
523 h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, size,
524 GNUNET_TIME_UNIT_FOREVER_REL,
525 GNUNET_YES, /* retry is OK in the initial stage */
526 &do_send_message, h);
527 GNUNET_assert (NULL != h->th);
533 * Cancel an ongoing computation or revoke our collaboration offer.
534 * Closes the connection to the service
536 * @param h computation handle to terminate
539 GNUNET_SCALARPRODUCT_cancel (struct GNUNET_SCALARPRODUCT_ComputationHandle *h)
543 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
546 GNUNET_free_non_null (h->elements);
547 GNUNET_free_non_null (h->msg);
548 if (NULL != h->client)
550 GNUNET_CLIENT_disconnect (h->client);
557 /* end of scalarproduct_api.c */