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 * Entry in the request queue per client
44 struct GNUNET_SCALARPRODUCT_ComputationHandle
47 * This is a linked list.
49 struct GNUNET_SCALARPRODUCT_ComputationHandle *next;
52 * This is a linked list.
54 struct GNUNET_SCALARPRODUCT_ComputationHandle *prev;
59 const struct GNUNET_CONFIGURATION_Handle *cfg;
62 * Current connection to the scalarproduct service.
64 struct GNUNET_CLIENT_Connection *client;
67 * Handle for statistics.
69 struct GNUNET_STATISTICS_Handle *stats;
72 * The shared session key identifying this computation
74 struct GNUNET_HashCode * key;
77 * Current transmit handle.
79 struct GNUNET_CLIENT_TransmitHandle *th;
84 uint16_t message_size;
87 * Message to be sent to the scalarproduct service
89 struct GNUNET_SCALARPRODUCT_client_request * msg;
94 * Function to call after transmission of the request.
96 GNUNET_SCALARPRODUCT_ContinuationWithStatus cont_status;
99 * Function to call after transmission of the request.
101 GNUNET_SCALARPRODUCT_DatumProcessor cont_datum;
105 * Closure for 'cont'.
110 * Response Processor for response from the service. This function calls the
111 * continuation function provided by the client.
113 GNUNET_SCALARPRODUCT_ResponseMessageHandler response_proc;
116 /**************************************************************
117 *** Global Variables **********
118 **************************************************************/
120 * Head of the active sessions queue
122 static struct GNUNET_SCALARPRODUCT_ComputationHandle *head;
124 * Tail of the active sessions queue
126 static struct GNUNET_SCALARPRODUCT_ComputationHandle *tail;
128 /**************************************************************
129 *** Function Declarations **********
130 **************************************************************/
133 GNUNET_SCALARPRODUCT_cancel (struct GNUNET_SCALARPRODUCT_ComputationHandle * h);
135 /**************************************************************
136 *** Static Function Declarations **********
137 **************************************************************/
141 * Handles the RESULT received in reply of prepare_response from the
144 * @param cls Handle to the Master Context
145 * @param msg Pointer to the response received
148 process_status_message (void *cls,
149 const struct GNUNET_MessageHeader *msg,
150 enum GNUNET_SCALARPRODUCT_ResponseStatus status)
152 struct GNUNET_SCALARPRODUCT_ComputationHandle *qe = cls;
154 qe->cont_status (qe->cont_cls, status);
159 * Handles the RESULT received in reply of prepare_response from the
162 * @param cls Handle to the Master Context
163 * @param msg Pointer to the response received
166 process_result_message (void *cls,
167 const struct GNUNET_MessageHeader *msg,
168 enum GNUNET_SCALARPRODUCT_ResponseStatus status)
170 struct GNUNET_SCALARPRODUCT_ComputationHandle *qe = cls;
171 const struct GNUNET_SCALARPRODUCT_client_response *message =
172 (const struct GNUNET_SCALARPRODUCT_client_response *) msg;
173 gcry_mpi_t result = NULL;
176 if (GNUNET_SCALARPRODUCT_Status_Success == status
177 && qe->cont_datum != NULL)
179 size_t product_len = ntohl (message->product_length);
180 result = gcry_mpi_new (0);
187 if (0 != (rc = gcry_mpi_scan (&num, GCRYMPI_FMT_STD, &msg[1], product_len, &read)))
189 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
190 gcry_mpi_release (result);
192 status = GNUNET_SCALARPRODUCT_Status_InvalidResponse;
196 if (message->range > 0)
197 gcry_mpi_add (result, result, num);
199 gcry_mpi_sub (result, result, num);
200 gcry_mpi_release (num);
204 qe->cont_datum (qe->cont_cls, status, result);
209 * Called when a response is received from the service. After basic check
210 * handler in qe->response_proc is called. This functions handles the response
211 * to the client which used the API.
213 * @param cls Pointer to the Master Context
214 * @param msg Pointer to the data received in response
217 receive_cb (void *cls, const struct GNUNET_MessageHeader *msg)
219 struct GNUNET_SCALARPRODUCT_ComputationHandle *qe = cls;
220 const struct GNUNET_SCALARPRODUCT_client_response *message =
221 (const struct GNUNET_SCALARPRODUCT_client_response *) msg;
222 enum GNUNET_SCALARPRODUCT_ResponseStatus status = GNUNET_SCALARPRODUCT_Status_InvalidResponse;
226 LOG (GNUNET_ERROR_TYPE_WARNING, "Disconnected by Service.\n");
227 status = GNUNET_SCALARPRODUCT_Status_ServiceDisconnected;
229 else if (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_SERVICE_TO_CLIENT != ntohs (msg->type))
231 LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid message type received\n");
233 else if (0 < ntohl (message->product_length) || (0 == message->range))
235 // response for the responder client, successful
236 GNUNET_STATISTICS_update (qe->stats,
237 gettext_noop ("# SUC responder result messages received"), 1,
240 status = GNUNET_SCALARPRODUCT_Status_Success;
243 if (qe->cont_datum != NULL)
244 qe->response_proc (qe, msg, status);
251 * Transmits the request to the VectorProduct Sevice
254 * @param size Size of the buffer
255 * @param buf Pointer to the buffer
257 * @return Size of the message sent
260 transmit_request (void *cls, size_t size,
263 struct GNUNET_SCALARPRODUCT_ComputationHandle *qe = cls;
267 LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to transmit request to SCALARPRODUCT.\n");
268 GNUNET_STATISTICS_update (qe->stats,
269 gettext_noop ("# transmission request failures"),
272 // notify caller about the error, done here.
273 if (qe->cont_datum != NULL)
274 qe->response_proc (qe, NULL, GNUNET_SCALARPRODUCT_Status_Failure);
275 GNUNET_SCALARPRODUCT_cancel (cls);
278 memcpy (buf, qe->msg, size);
280 GNUNET_free (qe->msg);
284 GNUNET_CLIENT_receive (qe->client, &receive_cb, qe,
285 GNUNET_TIME_UNIT_FOREVER_REL);
287 #if INSANE_STATISTICS
288 GNUNET_STATISTICS_update (qe->stats,
289 gettext_noop ("# bytes sent to scalarproduct"), 1,
296 /**************************************************************
298 **************************************************************/
302 * Used by Bob's client to cooperate with Alice,
304 * @param h handle to the master context
305 * @param key Session key - unique to the requesting client
306 * @param elements Array of elements of the vector
307 * @param element_count Number of elements in the vector
308 * @param cont Callback function
309 * @param cont_cls Closure for the callback function
311 struct GNUNET_SCALARPRODUCT_ComputationHandle *
312 GNUNET_SCALARPRODUCT_response (const struct GNUNET_CONFIGURATION_Handle *cfg,
313 const struct GNUNET_HashCode * key,
314 const int32_t * elements,
315 uint32_t element_count,
316 GNUNET_SCALARPRODUCT_ContinuationWithStatus cont,
319 struct GNUNET_SCALARPRODUCT_ComputationHandle *h;
320 struct GNUNET_SCALARPRODUCT_client_request *msg;
326 GNUNET_assert (elements);
327 GNUNET_assert (cont);
328 GNUNET_assert (element_count > 1);
329 GNUNET_assert (GNUNET_SERVER_MAX_MESSAGE_SIZE >= sizeof (struct GNUNET_SCALARPRODUCT_client_request)
330 +element_count * sizeof (int32_t));
331 h = GNUNET_new (struct GNUNET_SCALARPRODUCT_ComputationHandle);
332 h->client = GNUNET_CLIENT_connect ("scalarproduct", cfg);
335 LOG (GNUNET_ERROR_TYPE_ERROR,
336 _ ("Failed to connect to the scalarproduct service\n"));
340 h->stats = GNUNET_STATISTICS_create ("scalarproduct-api", cfg);
343 LOG (GNUNET_ERROR_TYPE_ERROR,
344 _ ("Failed to send a message to the statistics service\n"));
345 GNUNET_CLIENT_disconnect (h->client);
350 size = sizeof (struct GNUNET_SCALARPRODUCT_client_request) +element_count * sizeof (int32_t);
352 h->cont_status = cont;
353 h->cont_cls = cont_cls;
354 h->response_proc = &process_status_message;
356 memcpy (&h->key, key, sizeof (struct GNUNET_HashCode));
358 msg = (struct GNUNET_SCALARPRODUCT_client_request*) GNUNET_malloc (size);
360 msg->header.size = htons (size);
361 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB);
362 msg->element_count = htonl (element_count);
364 vector = (int32_t*) & msg[1];
365 // copy each element over to the message
366 for (i = 0; i < element_count; i++)
367 vector[i] = htonl (elements[i]);
369 memcpy (&msg->key, key, sizeof (struct GNUNET_HashCode));
371 h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, size,
372 GNUNET_TIME_UNIT_FOREVER_REL,
373 GNUNET_YES, // retry is OK in the initial stage
374 &transmit_request, h);
377 LOG (GNUNET_ERROR_TYPE_ERROR,
378 _ ("Failed to send a message to the scalarproduct service\n"));
379 GNUNET_STATISTICS_destroy (h->stats, GNUNET_YES);
380 GNUNET_CLIENT_disconnect (h->client);
381 GNUNET_free (h->msg);
385 GNUNET_CONTAINER_DLL_insert (head, tail, h);
391 * Request by Alice's client for computing a scalar product
393 * @param h handle to the master context
394 * @param key Session key - unique to the requesting client
395 * @param peer PeerID of the other peer
396 * @param elements Array of elements of the vector
397 * @param element_count Number of elements in the vector
398 * @param mask Array of the mask
399 * @param mask_bytes number of bytes in the mask
400 * @param cont Callback function
401 * @param cont_cls Closure for the callback function
403 struct GNUNET_SCALARPRODUCT_ComputationHandle *
404 GNUNET_SCALARPRODUCT_request (const struct GNUNET_CONFIGURATION_Handle *cfg,
405 const struct GNUNET_HashCode * key,
406 const struct GNUNET_PeerIdentity *peer,
407 const int32_t * elements,
408 uint32_t element_count,
409 const unsigned char * mask,
411 GNUNET_SCALARPRODUCT_DatumProcessor cont,
414 struct GNUNET_SCALARPRODUCT_ComputationHandle *h;
415 struct GNUNET_SCALARPRODUCT_client_request *msg;
420 GNUNET_assert (GNUNET_SERVER_MAX_MESSAGE_SIZE >= sizeof (struct GNUNET_SCALARPRODUCT_client_request)
421 +element_count * sizeof (int32_t)
424 h = GNUNET_new (struct GNUNET_SCALARPRODUCT_ComputationHandle);
425 h->client = GNUNET_CLIENT_connect ("scalarproduct", cfg);
428 LOG (GNUNET_ERROR_TYPE_ERROR,
429 _ ("Failed to connect to the scalarproduct service\n"));
433 h->stats = GNUNET_STATISTICS_create ("scalarproduct-api", cfg);
436 LOG (GNUNET_ERROR_TYPE_ERROR,
437 _ ("Failed to send a message to the statistics service\n"));
438 GNUNET_CLIENT_disconnect (h->client);
443 size = sizeof (struct GNUNET_SCALARPRODUCT_client_request) + element_count * sizeof (int32_t) + mask_bytes;
445 h->cont_datum = cont;
446 h->cont_cls = cont_cls;
447 h->response_proc = &process_result_message;
449 memcpy (&h->key, key, sizeof (struct GNUNET_HashCode));
451 msg = (struct GNUNET_SCALARPRODUCT_client_request*) GNUNET_malloc (size);
453 msg->header.size = htons (size);
454 msg->header.type = htons (GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_ALICE);
455 msg->element_count = htonl (element_count);
456 msg->mask_length = htonl (mask_bytes);
458 vector = (int32_t*) & msg[1];
459 // copy each element over to the message
460 for (i = 0; i < element_count; i++)
461 vector[i] = htonl (elements[i]);
463 memcpy (&msg->peer, peer, sizeof (struct GNUNET_PeerIdentity));
464 memcpy (&msg->key, key, sizeof (struct GNUNET_HashCode));
465 memcpy (&vector[element_count], mask, mask_bytes);
467 h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, size,
468 GNUNET_TIME_UNIT_FOREVER_REL,
469 GNUNET_YES, // retry is OK in the initial stage
470 &transmit_request, h);
473 LOG (GNUNET_ERROR_TYPE_ERROR,
474 _ ("Failed to send a message to the scalarproduct service\n"));
475 GNUNET_STATISTICS_destroy (h->stats, GNUNET_YES);
476 GNUNET_CLIENT_disconnect (h->client);
477 GNUNET_free (h->msg);
481 GNUNET_CONTAINER_DLL_insert (head, tail, h);
487 * Disconnect from the scalarproduct service.
489 * @param h a computation handle to cancel
492 GNUNET_SCALARPRODUCT_cancel (struct GNUNET_SCALARPRODUCT_ComputationHandle * h)
494 struct GNUNET_SCALARPRODUCT_ComputationHandle * qe;
496 for (qe = head; head != NULL; qe = head)
500 GNUNET_CONTAINER_DLL_remove (head, tail, qe);
502 GNUNET_CLIENT_notify_transmit_ready_cancel (qe->th);
503 GNUNET_CLIENT_disconnect (qe->client);
504 GNUNET_STATISTICS_destroy (qe->stats, GNUNET_YES);
505 GNUNET_free (qe->msg);
512 * Cancel ALL our ongoing scalar product computations and collaboration offers.
513 * Closes ALL connections to the service
516 GNUNET_SCALARPRODUCT_disconnect ()
518 struct GNUNET_SCALARPRODUCT_ComputationHandle * qe;
520 LOG (GNUNET_ERROR_TYPE_INFO, "Disconnecting from VectorProduct\n");
521 for (qe = head; head != NULL; qe = head)
523 GNUNET_CONTAINER_DLL_remove (head, tail, qe);
525 GNUNET_CLIENT_notify_transmit_ready_cancel (qe->th);
526 GNUNET_CLIENT_disconnect (qe->client);
527 GNUNET_STATISTICS_destroy (qe->stats, GNUNET_YES);
528 GNUNET_free (qe->msg);
533 /* end of ext_api.c */