2 This file is part of GNUnet.
3 (C) 2013 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.
22 * @file scalarproduct/scalarproduct_api.c
23 * @brief API for the scalarproduct
24 * @author Christian Fuchs
25 * @author Gaurav Kukreja
29 #include "gnunet_util_lib.h"
30 #include "gnunet_statistics_service.h"
31 #include "gnunet_scalarproduct_service.h"
32 #include "gnunet_protocols.h"
33 #include "scalarproduct.h"
35 #define LOG(kind,...) GNUNET_log_from (kind, "scalarproduct-api",__VA_ARGS__)
37 /**************************************************************
38 *** Datatype Declarations **********
39 **************************************************************/
42 * the abstraction function for our internal callback
44 typedef void (*GNUNET_SCALARPRODUCT_ResponseMessageHandler) (void *cls,
45 const struct GNUNET_MessageHeader *msg,
46 enum GNUNET_SCALARPRODUCT_ResponseStatus status);
49 * A handle returned for each computation
51 struct GNUNET_SCALARPRODUCT_ComputationHandle
56 const struct GNUNET_CONFIGURATION_Handle *cfg;
59 * Current connection to the scalarproduct service.
61 struct GNUNET_CLIENT_Connection *client;
64 * Handle for statistics.
66 struct GNUNET_STATISTICS_Handle *stats;
69 * The shared session key identifying this computation
71 struct GNUNET_HashCode key;
74 * Current transmit handle.
76 struct GNUNET_CLIENT_TransmitHandle *th;
79 * count of all elements we offer for computation
81 uint32_t element_count_total;
84 * count of the transfered elements we offer for computation
86 uint32_t element_count_transfered;
89 * the client's elements which
91 struct GNUNET_SCALARPRODUCT_Element * elements;
94 * Message to be sent to the scalarproduct service
99 * The client's msg handler callback
104 * Function to call after transmission of the request (Bob).
106 GNUNET_SCALARPRODUCT_ContinuationWithStatus cont_status;
109 * Function to call after transmission of the request (Alice).
111 GNUNET_SCALARPRODUCT_DatumProcessor cont_datum;
115 * Closure for 'cont'.
120 * API internal callback for results and failures to be forwarded to the client
122 GNUNET_SCALARPRODUCT_ResponseMessageHandler response_proc;
127 GNUNET_SCHEDULER_TaskIdentifier cont_multipart;
130 /**************************************************************
131 *** Forward Function Declarations **********
132 **************************************************************/
135 GNUNET_SCALARPRODUCT_cancel (struct GNUNET_SCALARPRODUCT_ComputationHandle * h);
137 static size_t do_send_message (void *cls, size_t size, void *buf);
138 /**************************************************************
139 *** Static Function Declarations **********
140 **************************************************************/
144 * Handles the STATUS received from the service for a response, does not contain a payload
146 * @param cls our Handle
147 * @param msg Pointer to the response received
148 * @param status the condition the request was terminated with (eg: disconnect)
151 process_status_message (void *cls,
152 const struct GNUNET_MessageHeader *msg,
153 enum GNUNET_SCALARPRODUCT_ResponseStatus status)
155 struct GNUNET_SCALARPRODUCT_ComputationHandle *qe = cls;
157 qe->cont_status (qe->cont_cls, status);
162 * Handles the RESULT received from the service for a request, should contain a result MPI value
164 * @param cls our Handle
165 * @param msg Pointer to the response received
166 * @param status the condition the request was terminated with (eg: disconnect)
169 process_result_message (void *cls,
170 const struct GNUNET_MessageHeader *msg,
171 enum GNUNET_SCALARPRODUCT_ResponseStatus status)
173 struct GNUNET_SCALARPRODUCT_ComputationHandle *qe = cls;
174 const struct GNUNET_SCALARPRODUCT_client_response *message =
175 (const struct GNUNET_SCALARPRODUCT_client_response *) msg;
176 gcry_mpi_t result = NULL;
179 if (GNUNET_SCALARPRODUCT_Status_Success == status)
181 size_t product_len = ntohl (message->product_length);
182 result = gcry_mpi_new (0);
189 if (0 != (rc = gcry_mpi_scan (&num, GCRYMPI_FMT_STD, &message[1], product_len, &read)))
191 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
192 gcry_mpi_release (result);
194 status = GNUNET_SCALARPRODUCT_Status_InvalidResponse;
198 if (0 < message->range)
199 gcry_mpi_add (result, result, num);
200 else if (0 > message->range)
201 gcry_mpi_sub (result, result, num);
202 gcry_mpi_release (num);
206 qe->cont_datum (qe->cont_cls, status, result);
211 * Called when a response is received from the service. After basic check, the
212 * handler in qe->response_proc is called. This functions handles the response
213 * to the client which used the API.
215 * @param cls Pointer to the Master Context
216 * @param msg Pointer to the data received in response
219 receive_cb (void *cls, const struct GNUNET_MessageHeader *msg)
221 struct GNUNET_SCALARPRODUCT_ComputationHandle *h = cls;
222 const struct GNUNET_SCALARPRODUCT_client_response *message =
223 (const struct GNUNET_SCALARPRODUCT_client_response *) msg;
224 enum GNUNET_SCALARPRODUCT_ResponseStatus status = GNUNET_SCALARPRODUCT_Status_InvalidResponse;
228 LOG (GNUNET_ERROR_TYPE_WARNING, "Disconnected by Service.\n");
229 status = GNUNET_SCALARPRODUCT_Status_ServiceDisconnected;
231 else if ((GNUNET_SYSERR != message->status) && (0 < message->product_length ))
233 // response for the responder client, successful
234 GNUNET_STATISTICS_update (h->stats,
235 gettext_noop ("# SUC responder result messages received"), 1,
238 status = GNUNET_SCALARPRODUCT_Status_Success;
240 else if (message->status == GNUNET_SYSERR){
241 // service signaled an error
242 status = GNUNET_SCALARPRODUCT_Status_Failure;
245 if (h->cont_status != NULL)
246 h->response_proc (h, msg, status);
253 send_multipart (void * cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
255 struct GNUNET_SCALARPRODUCT_ComputationHandle *h = (struct GNUNET_SCALARPRODUCT_ComputationHandle *) cls;
256 struct GNUNET_SCALARPRODUCT_computation_message_multipart *msg;
260 h->cont_multipart = GNUNET_SCHEDULER_NO_TASK;
262 todo = h->element_count_total - h->element_count_transfered;
263 size = sizeof (struct GNUNET_SCALARPRODUCT_computation_message_multipart) +todo * sizeof (struct GNUNET_SCALARPRODUCT_Element);
264 if (GNUNET_SERVER_MAX_MESSAGE_SIZE <= size) {
265 //create a multipart msg, first we calculate a new msg size for the head msg
266 todo = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct GNUNET_SCALARPRODUCT_computation_message_multipart)) / sizeof (struct GNUNET_SCALARPRODUCT_Element);
267 size = sizeof (struct GNUNET_SCALARPRODUCT_computation_message_multipart) +todo * sizeof (struct GNUNET_SCALARPRODUCT_Element);
270 msg = (struct GNUNET_SCALARPRODUCT_computation_message_multipart*) GNUNET_malloc (size);
272 msg->header.size = htons (size);
273 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART);
274 msg->element_count_contained = htonl (todo);
276 memcpy (&msg[1], &h->elements[h->element_count_transfered], todo * sizeof (struct GNUNET_SCALARPRODUCT_Element));
277 h->element_count_transfered += todo;
279 h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, size,
280 GNUNET_TIME_UNIT_FOREVER_REL,
281 GNUNET_YES, // retry is OK in the initial stage
282 &do_send_message, h);
285 LOG (GNUNET_ERROR_TYPE_ERROR,
286 _ ("Failed to send a multipart message to the scalarproduct service\n"));
287 GNUNET_STATISTICS_update (h->stats,
288 gettext_noop ("# transmission request failures"),
290 GNUNET_STATISTICS_destroy (h->stats, GNUNET_YES);
291 GNUNET_CLIENT_disconnect (h->client);
292 GNUNET_free (h->msg);
294 if (h->cont_status != NULL)
295 h->response_proc (h, NULL, GNUNET_SCALARPRODUCT_Status_Failure);
297 GNUNET_SCALARPRODUCT_cancel (cls);
302 * Transmits the request to the VectorProduct Service
305 * @param size Size of the buffer
306 * @param buf Pointer to the buffer
308 * @return Size of the message sent
311 do_send_message (void *cls, size_t size,
314 struct GNUNET_SCALARPRODUCT_ComputationHandle *h = cls;
317 LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to transmit request to SCALARPRODUCT.\n");
318 GNUNET_STATISTICS_update (h->stats,
319 gettext_noop ("# transmission request failures"),
322 // notify caller about the error, done here.
323 if (h->cont_status != NULL)
324 h->response_proc (h, NULL, GNUNET_SCALARPRODUCT_Status_Failure);
326 GNUNET_SCALARPRODUCT_cancel (cls);
329 memcpy (buf, h->msg, size);
331 GNUNET_free (h->msg);
335 #if INSANE_STATISTICS
336 GNUNET_STATISTICS_update (h->stats,
337 gettext_noop ("# bytes sent to scalarproduct"), 1,
342 if (h->element_count_total == h->element_count_transfered) {
343 GNUNET_CLIENT_receive (h->client, &receive_cb, h,
344 GNUNET_TIME_UNIT_FOREVER_REL);
348 h->cont_multipart = GNUNET_SCHEDULER_add_now (&send_multipart, h);
354 /**************************************************************
356 **************************************************************/
360 * Used by Bob's client to cooperate with Alice,
362 * @param cfg the gnunet configuration handle
363 * @param key Session key unique to the requesting client
364 * @param elements Array of elements of the vector
365 * @param element_count Number of elements in the vector
366 * @param cont Callback function
367 * @param cont_cls Closure for the callback function
369 * @return a new handle for this computation
371 struct GNUNET_SCALARPRODUCT_ComputationHandle *
372 GNUNET_SCALARPRODUCT_accept_computation (const struct GNUNET_CONFIGURATION_Handle * cfg,
373 const struct GNUNET_HashCode * session_key,
374 const struct GNUNET_SCALARPRODUCT_Element * elements,
375 uint32_t element_count,
376 GNUNET_SCALARPRODUCT_ContinuationWithStatus cont,
379 struct GNUNET_SCALARPRODUCT_ComputationHandle *h;
380 struct GNUNET_SCALARPRODUCT_computation_message *msg;
384 GNUNET_assert (GNUNET_SERVER_MAX_MESSAGE_SIZE >= sizeof (struct GNUNET_SCALARPRODUCT_computation_message)
385 + element_count * sizeof (int32_t));
386 h = GNUNET_new (struct GNUNET_SCALARPRODUCT_ComputationHandle);
387 h->client = GNUNET_CLIENT_connect ("scalarproduct", cfg);
390 LOG (GNUNET_ERROR_TYPE_ERROR,
391 _ ("Failed to connect to the scalarproduct service\n"));
395 h->stats = GNUNET_STATISTICS_create ("scalarproduct-api", cfg);
398 LOG (GNUNET_ERROR_TYPE_ERROR,
399 _ ("Failed to send a message to the statistics service\n"));
400 GNUNET_CLIENT_disconnect (h->client);
405 h->element_count_total = element_count;
406 size = sizeof (struct GNUNET_SCALARPRODUCT_computation_message) + element_count * sizeof (struct GNUNET_SCALARPRODUCT_Element);
407 if (GNUNET_SERVER_MAX_MESSAGE_SIZE > size) {
408 possible = element_count;
409 h->element_count_transfered = element_count;
412 //create a multipart msg, first we calculate a new msg size for the head msg
413 possible = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct GNUNET_SCALARPRODUCT_computation_message)) / sizeof (struct GNUNET_SCALARPRODUCT_Element);
414 h->element_count_transfered = possible;
415 size = sizeof (struct GNUNET_SCALARPRODUCT_computation_message) + possible*sizeof (struct GNUNET_SCALARPRODUCT_Element);
416 h->elements = (struct GNUNET_SCALARPRODUCT_Element*)
417 GNUNET_malloc (sizeof(struct GNUNET_SCALARPRODUCT_Element) * element_count);
418 memcpy (h->elements, elements, sizeof (struct GNUNET_SCALARPRODUCT_Element)*element_count);
421 h->cont_status = cont;
422 h->cont_cls = cont_cls;
423 h->response_proc = &process_status_message;
425 memcpy (&h->key, session_key, sizeof (struct GNUNET_HashCode));
427 msg = (struct GNUNET_SCALARPRODUCT_computation_message*) GNUNET_malloc (size);
429 msg->header.size = htons (size);
430 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB);
431 msg->element_count_total = htonl (element_count);
432 msg->element_count_contained = htonl (possible);
434 memcpy (&msg->session_key, session_key, sizeof (struct GNUNET_HashCode));
435 memcpy (&msg[1], elements, possible);
437 h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, size,
438 GNUNET_TIME_UNIT_FOREVER_REL,
439 GNUNET_YES, // retry is OK in the initial stage
440 &do_send_message, h);
443 LOG (GNUNET_ERROR_TYPE_ERROR,
444 _ ("Failed to send a message to the scalarproduct service\n"));
445 GNUNET_STATISTICS_update (h->stats,
446 gettext_noop ("# transmission request failures"),
448 GNUNET_STATISTICS_destroy (h->stats, GNUNET_YES);
449 GNUNET_CLIENT_disconnect (h->client);
450 GNUNET_free (h->msg);
451 GNUNET_free_non_null (h->elements);
460 * Request by Alice's client for computing a scalar product
462 * @param cfg the gnunet configuration handle
463 * @param session_key Session key should be unique to the requesting client
464 * @param peer PeerID of the other peer
465 * @param elements Array of elements of the vector
466 * @param element_count Number of elements in the vector
467 * @param cont Callback function
468 * @param cont_cls Closure for the callback function
470 * @return a new handle for this computation
472 struct GNUNET_SCALARPRODUCT_ComputationHandle *
473 GNUNET_SCALARPRODUCT_start_computation (const struct GNUNET_CONFIGURATION_Handle * cfg,
474 const struct GNUNET_HashCode * session_key,
475 const struct GNUNET_PeerIdentity *peer,
476 const struct GNUNET_SCALARPRODUCT_Element * elements,
477 uint32_t element_count,
478 GNUNET_SCALARPRODUCT_DatumProcessor cont,
481 struct GNUNET_SCALARPRODUCT_ComputationHandle *h;
482 struct GNUNET_SCALARPRODUCT_computation_message *msg;
486 h = GNUNET_new (struct GNUNET_SCALARPRODUCT_ComputationHandle);
487 h->client = GNUNET_CLIENT_connect ("scalarproduct", cfg);
490 LOG (GNUNET_ERROR_TYPE_ERROR,
491 _ ("Failed to connect to the scalarproduct service\n"));
495 h->stats = GNUNET_STATISTICS_create ("scalarproduct-api", cfg);
498 LOG (GNUNET_ERROR_TYPE_ERROR,
499 _ ("Failed to send a message to the statistics service\n"));
500 GNUNET_CLIENT_disconnect (h->client);
505 h->element_count_total = element_count;
506 size = sizeof (struct GNUNET_SCALARPRODUCT_computation_message) + element_count * sizeof (struct GNUNET_SCALARPRODUCT_Element);
507 if (GNUNET_SERVER_MAX_MESSAGE_SIZE > size) {
508 possible = element_count;
509 h->element_count_transfered = element_count;
512 //create a multipart msg, first we calculate a new msg size for the head msg
513 possible = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct GNUNET_SCALARPRODUCT_computation_message)) / sizeof (struct GNUNET_SCALARPRODUCT_Element);
514 h->element_count_transfered = possible;
515 size = sizeof (struct GNUNET_SCALARPRODUCT_computation_message) + possible*sizeof (struct GNUNET_SCALARPRODUCT_Element);
516 h->elements = (struct GNUNET_SCALARPRODUCT_Element*)
517 GNUNET_malloc (sizeof(struct GNUNET_SCALARPRODUCT_Element) * element_count);
518 memcpy (h->elements, elements, sizeof (struct GNUNET_SCALARPRODUCT_Element) * element_count);
521 h->cont_datum = cont;
522 h->cont_cls = cont_cls;
523 h->response_proc = &process_result_message;
525 memcpy (&h->key, session_key, sizeof (struct GNUNET_HashCode));
527 msg = (struct GNUNET_SCALARPRODUCT_computation_message*) GNUNET_malloc (size);
529 msg->header.size = htons (size);
530 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE);
531 msg->element_count_total = htonl (element_count);
532 msg->element_count_contained = htonl (possible);
534 memcpy (&msg->peer, peer, sizeof (struct GNUNET_PeerIdentity));
535 memcpy (&msg->session_key, session_key, sizeof (struct GNUNET_HashCode));
536 memcpy (&msg[1], elements, sizeof (struct GNUNET_SCALARPRODUCT_Element) * possible);
538 h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, size,
539 GNUNET_TIME_UNIT_FOREVER_REL,
540 GNUNET_YES, // retry is OK in the initial stage
541 &do_send_message, h);
544 LOG (GNUNET_ERROR_TYPE_ERROR,
545 _ ("Failed to send a message to the scalarproduct service\n"));
546 GNUNET_STATISTICS_update (h->stats,
547 gettext_noop ("# transmission request failures"),
549 GNUNET_STATISTICS_destroy (h->stats, GNUNET_YES);
550 GNUNET_CLIENT_disconnect (h->client);
551 GNUNET_free (h->msg);
552 GNUNET_free_non_null (h->elements);
560 * Cancel an ongoing computation or revoke our collaboration offer.
561 * Closes the connection to the service
563 * @param h computation handle to terminate
566 GNUNET_SCALARPRODUCT_cancel (struct GNUNET_SCALARPRODUCT_ComputationHandle * h)
569 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
570 if (GNUNET_SCHEDULER_NO_TASK != h->cont_multipart)
571 GNUNET_SCHEDULER_cancel (h->cont_multipart);
572 GNUNET_free_non_null (h->elements);
573 GNUNET_free_non_null (h->msg);
574 GNUNET_CLIENT_disconnect (h->client);
575 GNUNET_STATISTICS_destroy (h->stats, GNUNET_YES);
580 /* end of scalarproduct_api.c */