2 This file is part of GNUnet.
3 (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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, 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
28 #include "gnunet_util_lib.h"
29 #include "gnunet_statistics_service.h"
30 #include "gnunet_scalarproduct_service.h"
31 #include "gnunet_protocols.h"
32 #include "scalarproduct.h"
34 #define LOG(kind,...) GNUNET_log_from (kind, "scalarproduct-api",__VA_ARGS__)
38 * The abstraction function for our internal callback
40 * @param h computation handle
41 * @param msg response we got, NULL on errors
42 * @param status processing status code
45 (*GNUNET_SCALARPRODUCT_ResponseMessageHandler) (struct GNUNET_SCALARPRODUCT_ComputationHandle *h,
46 const struct ClientResponseMessage *msg,
47 enum GNUNET_SCALARPRODUCT_ResponseStatus status);
51 * A handle returned for each computation
53 struct GNUNET_SCALARPRODUCT_ComputationHandle
58 const struct GNUNET_CONFIGURATION_Handle *cfg;
61 * Current connection to the scalarproduct service.
63 struct GNUNET_CLIENT_Connection *client;
66 * Current transmit handle.
68 struct GNUNET_CLIENT_TransmitHandle *th;
71 * the client's elements which
73 struct GNUNET_SCALARPRODUCT_Element *elements;
76 * Message to be sent to the scalarproduct service
78 struct GNUNET_MessageHeader *msg;
81 * Function to call after transmission of the request (Bob).
83 GNUNET_SCALARPRODUCT_ContinuationWithStatus cont_status;
86 * Function to call after transmission of the request (Alice).
88 GNUNET_SCALARPRODUCT_DatumProcessor cont_datum;
91 * Closure for @e cont_status or @e cont_datum.
96 * API internal callback for results and failures to be forwarded to
99 GNUNET_SCALARPRODUCT_ResponseMessageHandler response_proc;
102 * The shared session key identifying this computation
104 struct GNUNET_HashCode key;
107 * count of all @e elements we offer for computation
109 uint32_t element_count_total;
112 * count of the transfered @e elements we offer for computation
114 uint32_t element_count_transfered;
120 * Handles the STATUS received from the service for a response, does
121 * not contain a payload. Called when we participate as "Bob" via
122 * #GNUNET_SCALARPRODUCT_accept_computation().
124 * @param h our Handle
125 * @param msg the response received
126 * @param status the condition the request was terminated with (eg: disconnect)
129 process_status_message (struct GNUNET_SCALARPRODUCT_ComputationHandle *h,
130 const struct ClientResponseMessage *msg,
131 enum GNUNET_SCALARPRODUCT_ResponseStatus status)
133 if (NULL != h->cont_status)
134 h->cont_status (h->cont_cls,
136 GNUNET_SCALARPRODUCT_cancel (h);
141 * Handles the RESULT received from the service for a request, should
142 * contain a result MPI value. Called when we participate as "Alice" via
143 * #GNUNET_SCALARPRODUCT_start_computation().
145 * @param h our Handle
146 * @param msg Pointer to the response received
147 * @param status the condition the request was terminated with (eg: disconnect)
150 process_result_message (struct GNUNET_SCALARPRODUCT_ComputationHandle *h,
151 const struct ClientResponseMessage *msg,
152 enum GNUNET_SCALARPRODUCT_ResponseStatus status)
155 gcry_mpi_t result = NULL;
160 if ( (GNUNET_SCALARPRODUCT_Status_Success == status) &&
162 ( (ntohs (msg->header.size) - sizeof (struct ClientResponseMessage)
163 != (product_len = ntohl (msg->product_length))) ) ) )
166 status = GNUNET_SCALARPRODUCT_Status_InvalidResponse;
168 if (GNUNET_SCALARPRODUCT_Status_Success == status)
170 result = gcry_mpi_new (0);
175 if (0 != (rc = gcry_mpi_scan (&num, GCRYMPI_FMT_STD,
180 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
183 gcry_mpi_release (result);
185 status = GNUNET_SCALARPRODUCT_Status_InvalidResponse;
189 if (0 < ntohl (msg->range))
190 gcry_mpi_add (result, result, num);
191 else if (0 > ntohl (msg->range))
192 gcry_mpi_sub (result, result, num);
193 gcry_mpi_release (num);
197 h->cont_datum (h->cont_cls,
201 gcry_mpi_release (result);
202 GNUNET_SCALARPRODUCT_cancel (h);
207 * Called when a response is received from the service. After basic check, the
208 * handler in qe->response_proc is called. This functions handles the response
209 * to the client which used the API.
211 * @param cls Pointer to the Master Context
212 * @param msg Pointer to the data received in response
215 receive_cb (void *cls,
216 const struct GNUNET_MessageHeader *msg)
218 struct GNUNET_SCALARPRODUCT_ComputationHandle *h = cls;
219 const struct ClientResponseMessage *message;
223 LOG (GNUNET_ERROR_TYPE_INFO,
224 "Disconnected from SCALARPRODUCT service.\n");
227 GNUNET_SCALARPRODUCT_Status_ServiceDisconnected);
230 if (ntohs (msg->size) != sizeof (struct ClientResponseMessage))
235 GNUNET_SCALARPRODUCT_Status_InvalidResponse);
238 message = (const struct ClientResponseMessage *) msg;
239 if (GNUNET_SYSERR == ntohl (message->status))
243 GNUNET_SCALARPRODUCT_Status_Failure);
248 GNUNET_SCALARPRODUCT_Status_Success);
253 * Transmits the request to the SCALARPRODUCT service
255 * @param cls Closure with the `struct GNUNET_SCALARPRODUCT_ComputationHandle`
256 * @param size Size of the buffer @a buf
257 * @param buf Pointer to the buffer
258 * @return Size of the message sent
261 do_send_message (void *cls,
265 struct GNUNET_SCALARPRODUCT_ComputationHandle *h = cls;
266 struct ComputationMultipartMessage *msg;
274 LOG (GNUNET_ERROR_TYPE_DEBUG,
275 "Failed to transmit request to SCALARPRODUCT.\n");
276 /* notify caller about the error, done here */
277 h->response_proc (h, NULL,
278 GNUNET_SCALARPRODUCT_Status_Failure);
281 ret = ntohs (h->msg->size);
282 memcpy (buf, h->msg, ret);
283 GNUNET_free (h->msg);
287 if (h->element_count_total == h->element_count_transfered)
289 GNUNET_CLIENT_receive (h->client,
291 GNUNET_TIME_UNIT_FOREVER_REL);
295 todo = h->element_count_total - h->element_count_transfered;
296 nsize = sizeof (struct ComputationMultipartMessage)
297 + todo * sizeof (struct GNUNET_SCALARPRODUCT_Element);
298 if (GNUNET_SERVER_MAX_MESSAGE_SIZE <= size)
300 /* cannot do all of them, limit to what is possible in one message */
301 todo = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct ComputationMultipartMessage))
302 / sizeof (struct GNUNET_SCALARPRODUCT_Element);
303 nsize = sizeof (struct ComputationMultipartMessage)
304 + todo * sizeof (struct GNUNET_SCALARPRODUCT_Element);
307 msg = GNUNET_malloc (nsize);
308 h->msg = &msg->header;
309 msg->header.size = htons (nsize);
310 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART);
311 msg->element_count_contained = htonl (todo);
313 &h->elements[h->element_count_transfered],
314 todo * sizeof (struct GNUNET_SCALARPRODUCT_Element));
315 h->element_count_transfered += todo;
316 h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, nsize,
317 GNUNET_TIME_UNIT_FOREVER_REL,
319 &do_send_message, h);
320 GNUNET_assert (NULL != h->th);
326 * Used by Bob's client to cooperate with Alice,
328 * @param cfg the gnunet configuration handle
329 * @param key Session key unique to the requesting client
330 * @param elements Array of elements of the vector
331 * @param element_count Number of elements in the @a elements vector
332 * @param cont Callback function
333 * @param cont_cls Closure for @a cont
334 * @return a new handle for this computation
336 struct GNUNET_SCALARPRODUCT_ComputationHandle *
337 GNUNET_SCALARPRODUCT_accept_computation (const struct GNUNET_CONFIGURATION_Handle *cfg,
338 const struct GNUNET_HashCode *session_key,
339 const struct GNUNET_SCALARPRODUCT_Element *elements,
340 uint32_t element_count,
341 GNUNET_SCALARPRODUCT_ContinuationWithStatus cont,
344 struct GNUNET_SCALARPRODUCT_ComputationHandle *h;
345 struct ComputationMessage *msg;
349 h = GNUNET_new (struct GNUNET_SCALARPRODUCT_ComputationHandle);
350 h->cont_status = cont;
351 h->cont_cls = cont_cls;
352 h->response_proc = &process_status_message;
354 h->key = *session_key;
355 h->client = GNUNET_CLIENT_connect ("scalarproduct", cfg);
356 h->element_count_total = element_count;
357 if (NULL == h->client)
359 /* scalarproduct configuration error */
364 size = sizeof (struct ComputationMessage)
365 + element_count * sizeof (struct GNUNET_SCALARPRODUCT_Element);
366 if (GNUNET_SERVER_MAX_MESSAGE_SIZE > size)
368 possible = element_count;
369 h->element_count_transfered = element_count;
373 /* create a multipart msg, first we calculate a new msg size for the head msg */
374 possible = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct ComputationMessage))
375 / sizeof (struct GNUNET_SCALARPRODUCT_Element);
376 h->element_count_transfered = possible;
377 size = sizeof (struct ComputationMessage)
378 + possible * sizeof (struct GNUNET_SCALARPRODUCT_Element);
379 h->elements = GNUNET_malloc (sizeof(struct GNUNET_SCALARPRODUCT_Element) * element_count);
382 sizeof (struct GNUNET_SCALARPRODUCT_Element) * element_count);
385 msg = GNUNET_malloc (size);
386 h->msg = &msg->header;
387 msg->header.size = htons (size);
388 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB);
389 msg->element_count_total = htonl (element_count);
390 msg->element_count_contained = htonl (possible);
391 msg->session_key = *session_key;
394 possible * sizeof (struct GNUNET_SCALARPRODUCT_Element));
395 h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, size,
396 GNUNET_TIME_UNIT_FOREVER_REL,
397 GNUNET_YES, /* retry is OK in the initial stage */
398 &do_send_message, h);
399 GNUNET_assert (NULL != h->th);
405 * Request by Alice's client for computing a scalar product
407 * @param cfg the gnunet configuration handle
408 * @param session_key Session key should be unique to the requesting client
409 * @param peer PeerID of the other peer
410 * @param elements Array of elements of the vector
411 * @param element_count Number of elements in the @a elements vector
412 * @param cont Callback function
413 * @param cont_cls Closure for @a cont
414 * @return a new handle for this computation
416 struct GNUNET_SCALARPRODUCT_ComputationHandle *
417 GNUNET_SCALARPRODUCT_start_computation (const struct GNUNET_CONFIGURATION_Handle *cfg,
418 const struct GNUNET_HashCode *session_key,
419 const struct GNUNET_PeerIdentity *peer,
420 const struct GNUNET_SCALARPRODUCT_Element *elements,
421 uint32_t element_count,
422 GNUNET_SCALARPRODUCT_DatumProcessor cont,
425 struct GNUNET_SCALARPRODUCT_ComputationHandle *h;
426 struct ComputationMessage *msg;
430 h = GNUNET_new (struct GNUNET_SCALARPRODUCT_ComputationHandle);
431 h->client = GNUNET_CLIENT_connect ("scalarproduct", cfg);
432 if (NULL == h->client)
434 /* missconfigured scalarproduct service */
439 h->element_count_total = element_count;
440 h->cont_datum = cont;
441 h->cont_cls = cont_cls;
442 h->response_proc = &process_result_message;
444 h->key = *session_key;
445 size = sizeof (struct ComputationMessage)
446 + element_count * sizeof (struct GNUNET_SCALARPRODUCT_Element);
447 if (GNUNET_SERVER_MAX_MESSAGE_SIZE > size)
449 possible = element_count;
450 h->element_count_transfered = element_count;
454 /* create a multipart msg, first we calculate a new msg size for the head msg */
455 possible = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct ComputationMessage))
456 / sizeof (struct GNUNET_SCALARPRODUCT_Element);
457 h->element_count_transfered = possible;
458 size = sizeof (struct ComputationMessage)
459 + possible * sizeof (struct GNUNET_SCALARPRODUCT_Element);
460 h->elements = GNUNET_malloc (sizeof(struct GNUNET_SCALARPRODUCT_Element) * element_count);
463 sizeof (struct GNUNET_SCALARPRODUCT_Element) * element_count);
466 msg = GNUNET_malloc (size);
467 h->msg = &msg->header;
468 msg->header.size = htons (size);
469 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE);
470 msg->element_count_total = htonl (element_count);
471 msg->element_count_contained = htonl (possible);
472 msg->reserved = htonl (0);
474 msg->session_key = *session_key;
477 sizeof (struct GNUNET_SCALARPRODUCT_Element) * possible);
478 h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, size,
479 GNUNET_TIME_UNIT_FOREVER_REL,
480 GNUNET_YES, /* retry is OK in the initial stage */
481 &do_send_message, h);
482 GNUNET_assert (NULL != h->th);
488 * Cancel an ongoing computation or revoke our collaboration offer.
489 * Closes the connection to the service
491 * @param h computation handle to terminate
494 GNUNET_SCALARPRODUCT_cancel (struct GNUNET_SCALARPRODUCT_ComputationHandle *h)
498 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
501 GNUNET_free_non_null (h->elements);
502 GNUNET_free_non_null (h->msg);
503 if (NULL != h->client)
505 GNUNET_CLIENT_disconnect (h->client);
512 /* end of scalarproduct_api.c */