2 This file is part of GNUnet.
3 Copyright (C) 2013-2015 GNUnet e.V.
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/gnunet-service-scalarproduct-ecc_bob.c
22 * @brief scalarproduct service implementation
23 * @author Christian M. Fuchs
24 * @author Christian Grothoff
29 #include "gnunet_util_lib.h"
30 #include "gnunet_core_service.h"
31 #include "gnunet_cadet_service.h"
32 #include "gnunet_applications.h"
33 #include "gnunet_protocols.h"
34 #include "gnunet_scalarproduct_service.h"
35 #include "gnunet_set_service.h"
36 #include "scalarproduct.h"
37 #include "gnunet-service-scalarproduct-ecc.h"
39 #define LOG(kind,...) GNUNET_log_from (kind, "scalarproduct-bob", __VA_ARGS__)
43 * An encrypted element key-value pair.
48 * Key used to identify matching pairs of values to multiply.
49 * Points into an existing data structure, to avoid copying
50 * and doubling memory use.
52 const struct GNUNET_HashCode *key;
55 * Value represented (a).
62 * An incoming session from CADET.
64 struct CadetIncomingSession;
68 * A scalarproduct session which tracks an offer for a
69 * multiplication service by a local client.
71 struct BobServiceSession
75 * (hopefully) unique transaction ID
77 struct GNUNET_HashCode session_id;
80 * The client this request is related to.
82 struct GNUNET_SERVER_Client *client;
85 * Client message queue.
87 struct GNUNET_MQ_Handle *client_mq;
90 * All non-0-value'd elements transmitted to us.
92 struct GNUNET_CONTAINER_MultiHashMap *intersected_elements;
95 * Set of elements for which we will be conducting an intersection.
96 * The resulting elements are then used for computing the scalar product.
98 struct GNUNET_SET_Handle *intersection_set;
101 * Set of elements for which will conduction an intersection.
102 * the resulting elements are then used for computing the scalar product.
104 struct GNUNET_SET_OperationHandle *intersection_op;
109 struct GNUNET_CADET_Port *port;
114 struct MpiElement *sorted_elements;
117 * Product of the g_i^{b_i}
119 gcry_mpi_point_t prod_g_i_b_i;
122 * Product of the h_i^{b_i}
124 gcry_mpi_point_t prod_h_i_b_i;
127 * Handle for our associated incoming CADET session, or NULL
128 * if we have not gotten one yet.
130 struct CadetIncomingSession *cadet;
133 * How many elements will be supplied in total from the client.
138 * Already transferred elements (received) for multipart
139 * messages from client. Always less than @e total.
141 uint32_t client_received_element_count;
144 * How many elements actually are used for the scalar product.
145 * Size of the arrays in @e r and @e r_prime. Also sometimes
146 * used as an index into the arrays during construction.
148 uint32_t used_element_count;
151 * Counts the number of values received from Alice by us.
152 * Always less than @e used_element_count.
154 uint32_t cadet_received_element_count;
157 * State of this session. In
158 * #GNUNET_SCALARPRODUCT_STATUS_ACTIVE while operation is
159 * ongoing, afterwards in #GNUNET_SCALARPRODUCT_STATUS_SUCCESS or
160 * #GNUNET_SCALARPRODUCT_STATUS_FAILURE.
162 enum GNUNET_SCALARPRODUCT_ResponseStatus status;
165 * Are we already in #destroy_service_session()?
173 * An incoming session from CADET.
175 struct CadetIncomingSession
179 * Associated client session, or NULL.
181 struct BobServiceSession *s;
186 struct GNUNET_CADET_Channel *channel;
189 * Originator's peer identity. (Only for diagnostics.)
191 struct GNUNET_PeerIdentity peer;
194 * (hopefully) unique transaction ID
196 struct GNUNET_HashCode session_id;
199 * The message queue for this channel.
201 struct GNUNET_MQ_Handle *cadet_mq;
204 * Has this CADET session been added to the map yet?
205 * #GNUNET_YES if so, in which case @e session_id is
211 * Are we already in #destroy_cadet_session()?
219 * GNUnet configuration handle
221 static const struct GNUNET_CONFIGURATION_Handle *cfg;
224 * Map of `struct BobServiceSession`, by session keys.
226 static struct GNUNET_CONTAINER_MultiHashMap *client_sessions;
229 * Map of `struct CadetIncomingSession`, by session keys.
231 static struct GNUNET_CONTAINER_MultiHashMap *cadet_sessions;
234 * Handle to the CADET service.
236 static struct GNUNET_CADET_Handle *my_cadet;
239 * Context for DLOG operations on a curve.
241 static struct GNUNET_CRYPTO_EccDlogContext *edc;
246 * Finds a not terminated client session in the respective map based on
249 * @param key the session key we want to search for
250 * @return the matching session, or NULL for none
252 static struct BobServiceSession *
253 find_matching_client_session (const struct GNUNET_HashCode *key)
255 return GNUNET_CONTAINER_multihashmap_get (client_sessions,
261 * Finds a CADET session in the respective map based on session key.
263 * @param key the session key we want to search for
264 * @return the matching session, or NULL for none
266 static struct CadetIncomingSession *
267 find_matching_cadet_session (const struct GNUNET_HashCode *key)
269 return GNUNET_CONTAINER_multihashmap_get (cadet_sessions,
275 * Callback used to free the elements in the map.
278 * @param key key of the element
279 * @param value the value to free
282 free_element_cb (void *cls,
283 const struct GNUNET_HashCode *key,
286 struct GNUNET_SCALARPRODUCT_Element *element = value;
288 GNUNET_free (element);
294 * Destroy session state, we are done with it.
296 * @param session the session to free elements from
299 destroy_cadet_session (struct CadetIncomingSession *s);
303 * Destroy session state, we are done with it.
305 * @param session the session to free elements from
308 destroy_service_session (struct BobServiceSession *s)
310 struct CadetIncomingSession *in;
313 if (GNUNET_YES == s->in_destroy)
315 s->in_destroy = GNUNET_YES;
316 if (NULL != (in = s->cadet))
319 destroy_cadet_session (in);
321 if (NULL != s->client_mq)
323 GNUNET_MQ_destroy (s->client_mq);
326 if (NULL != s->client)
328 GNUNET_SERVER_client_disconnect (s->client);
331 GNUNET_assert (GNUNET_YES ==
332 GNUNET_CONTAINER_multihashmap_remove (client_sessions,
335 if (NULL != s->intersected_elements)
337 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
340 GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements);
341 s->intersected_elements = NULL;
343 if (NULL != s->intersection_op)
345 GNUNET_SET_operation_cancel (s->intersection_op);
346 s->intersection_op = NULL;
348 if (NULL != s->intersection_set)
350 GNUNET_SET_destroy (s->intersection_set);
351 s->intersection_set = NULL;
353 if (NULL != s->sorted_elements)
355 for (i=0;i<s->used_element_count;i++)
356 gcry_mpi_release (s->sorted_elements[i].value);
357 GNUNET_free (s->sorted_elements);
358 s->sorted_elements = NULL;
360 if (NULL != s->prod_g_i_b_i)
362 gcry_mpi_point_release (s->prod_g_i_b_i);
363 s->prod_g_i_b_i = NULL;
365 if (NULL != s->prod_h_i_b_i)
367 gcry_mpi_point_release (s->prod_h_i_b_i);
368 s->prod_h_i_b_i = NULL;
370 GNUNET_CADET_close_port (s->port);
376 * Destroy incoming CADET session state, we are done with it.
378 * @param in the session to free elements from
381 destroy_cadet_session (struct CadetIncomingSession *in)
383 struct BobServiceSession *s;
385 if (GNUNET_YES == in->in_destroy)
387 in->in_destroy = GNUNET_YES;
388 if (NULL != (s = in->s))
391 destroy_service_session (s);
393 if (GNUNET_YES == in->in_map)
395 GNUNET_assert (GNUNET_YES ==
396 GNUNET_CONTAINER_multihashmap_remove (cadet_sessions,
399 in->in_map = GNUNET_NO;
401 if (NULL != in->cadet_mq)
403 GNUNET_MQ_destroy (in->cadet_mq);
406 if (NULL != in->channel)
408 GNUNET_CADET_channel_destroy (in->channel);
416 * Notify the client that the session has succeeded or failed. This
417 * message gets sent to Bob's client if the operation completed or
418 * Alice disconnected.
420 * @param session the associated client session to fail or succeed
423 prepare_client_end_notification (struct BobServiceSession *session)
425 struct ClientResponseMessage *msg;
426 struct GNUNET_MQ_Envelope *e;
428 if (NULL == session->client_mq)
429 return; /* no client left to be notified */
430 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
431 "Sending session-end notification with status %d to client for session %s\n",
433 GNUNET_h2s (&session->session_id));
434 e = GNUNET_MQ_msg (msg,
435 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
437 msg->product_length = htonl (0);
438 msg->status = htonl (session->status);
439 GNUNET_MQ_send (session->client_mq,
445 * Function called whenever a channel is destroyed. Should clean up
446 * any associated state.
448 * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
450 * @param cls closure (set from #GNUNET_CADET_connect())
451 * @param channel connection to the other end (henceforth invalid)
452 * @param channel_ctx place where local state associated
453 * with the channel is stored
456 cb_channel_destruction (void *cls,
457 const struct GNUNET_CADET_Channel *channel,
460 struct CadetIncomingSession *in = channel_ctx;
461 struct BobServiceSession *s;
463 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
464 "Peer disconnected, terminating session %s with peer %s\n",
465 GNUNET_h2s (&in->session_id),
466 GNUNET_i2s (&in->peer));
467 if (NULL != in->cadet_mq)
469 GNUNET_MQ_destroy (in->cadet_mq);
473 if (NULL != (s = in->s))
475 if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
477 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
478 prepare_client_end_notification (s);
481 destroy_cadet_session (in);
486 * MQ finished giving our last message to CADET, now notify
487 * the client that we are finished.
490 bob_cadet_done_cb (void *cls)
492 struct BobServiceSession *session = cls;
494 session->status = GNUNET_SCALARPRODUCT_STATUS_SUCCESS;
495 prepare_client_end_notification (session);
500 * Bob generates the response message to be sent to Alice.
502 * @param s the associated requesting session with Alice
505 transmit_bobs_cryptodata_message (struct BobServiceSession *s)
507 struct EccBobCryptodataMessage *msg;
508 struct GNUNET_MQ_Envelope *e;
510 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
511 "Sending response to Alice\n");
512 e = GNUNET_MQ_msg (msg,
513 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_BOB_CRYPTODATA);
514 msg->contained_element_count = htonl (2);
515 if (NULL != s->prod_g_i_b_i)
516 GNUNET_CRYPTO_ecc_point_to_bin (edc,
519 if (NULL != s->prod_h_i_b_i)
520 GNUNET_CRYPTO_ecc_point_to_bin (edc,
523 GNUNET_MQ_notify_sent (e,
526 GNUNET_MQ_send (s->cadet->cadet_mq,
532 * Iterator to copy over messages from the hash map
533 * into an array for sorting.
535 * @param cls the `struct BobServiceSession *`
536 * @param key the key (unused)
537 * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
538 * TODO: code duplication with Alice!
541 copy_element_cb (void *cls,
542 const struct GNUNET_HashCode *key,
545 struct BobServiceSession *s = cls;
546 struct GNUNET_SCALARPRODUCT_Element *e = value;
550 mval = gcry_mpi_new (0);
551 val = (int64_t) GNUNET_ntohll (e->value);
553 gcry_mpi_sub_ui (mval, mval, -val);
555 gcry_mpi_add_ui (mval, mval, val);
556 s->sorted_elements [s->used_element_count].value = mval;
557 s->sorted_elements [s->used_element_count].key = &e->key;
558 s->used_element_count++;
564 * Compare two `struct MpiValue`s by key for sorting.
566 * @param a pointer to first `struct MpiValue *`
567 * @param b pointer to first `struct MpiValue *`
568 * @return -1 for a < b, 0 for a=b, 1 for a > b.
569 * TODO: code duplication with Alice!
572 element_cmp (const void *a,
575 const struct MpiElement *ma = a;
576 const struct MpiElement *mb = b;
578 return GNUNET_CRYPTO_hash_cmp (ma->key,
584 * Handle a multipart-chunk of a request from another service to
585 * calculate a scalarproduct with us.
587 * @param cls closure (set from #GNUNET_CADET_connect)
588 * @param channel connection to the other end
589 * @param channel_ctx place to store local state associated with the @a channel
590 * @param message the actual message
591 * @return #GNUNET_OK to keep the connection open,
592 * #GNUNET_SYSERR to close it (signal serious error)
595 handle_alices_cryptodata_message (void *cls,
596 struct GNUNET_CADET_Channel *channel,
598 const struct GNUNET_MessageHeader *message)
600 struct CadetIncomingSession *in = *channel_ctx;
601 struct BobServiceSession *s;
602 const struct EccAliceCryptodataMessage *msg;
603 const struct GNUNET_CRYPTO_EccPoint *payload;
604 uint32_t contained_elements;
609 const struct MpiElement *b_i;
610 gcry_mpi_point_t tmp;
611 gcry_mpi_point_t g_i;
612 gcry_mpi_point_t h_i;
613 gcry_mpi_point_t g_i_b_i;
614 gcry_mpi_point_t h_i_b_i;
620 return GNUNET_SYSERR;
626 return GNUNET_SYSERR;
628 /* sort our vector for the computation */
629 if (NULL == s->sorted_elements)
632 = GNUNET_malloc (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements) *
633 sizeof (struct MpiElement));
634 s->used_element_count = 0;
635 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
638 qsort (s->sorted_elements,
639 s->used_element_count,
640 sizeof (struct MpiElement),
645 msize = ntohs (message->size);
646 if (msize <= sizeof (struct EccAliceCryptodataMessage))
649 return GNUNET_SYSERR;
651 msg = (const struct EccAliceCryptodataMessage *) message;
652 contained_elements = ntohl (msg->contained_element_count);
653 /* Our intersection may still be ongoing, but this is nevertheless
654 an upper bound on the required array size */
655 max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements);
656 msg_length = sizeof (struct EccAliceCryptodataMessage)
657 + contained_elements * sizeof (struct GNUNET_CRYPTO_EccPoint) * 2;
658 if ( (msize != msg_length) ||
659 (0 == contained_elements) ||
660 (contained_elements > UINT16_MAX) ||
661 (max < contained_elements + s->cadet_received_element_count) )
664 return GNUNET_SYSERR;
666 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
667 "Received %u crypto values from Alice\n",
668 (unsigned int) contained_elements);
669 payload = (const struct GNUNET_CRYPTO_EccPoint *) &msg[1];
671 for (i=0;i<contained_elements;i++)
673 b_i = &s->sorted_elements[i + s->cadet_received_element_count];
674 g_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
676 g_i_b_i = GNUNET_CRYPTO_ecc_pmul_mpi (edc,
679 gcry_mpi_point_release (g_i);
680 h_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
681 &payload[i * 2 + 1]);
682 h_i_b_i = GNUNET_CRYPTO_ecc_pmul_mpi (edc,
685 gcry_mpi_point_release (h_i);
686 if (0 == i + s->cadet_received_element_count)
688 /* first iteration, nothing to add */
689 s->prod_g_i_b_i = g_i_b_i;
690 s->prod_h_i_b_i = h_i_b_i;
694 /* further iterations, cummulate resulting value */
695 tmp = GNUNET_CRYPTO_ecc_add (edc,
698 gcry_mpi_point_release (s->prod_g_i_b_i);
699 gcry_mpi_point_release (g_i_b_i);
700 s->prod_g_i_b_i = tmp;
701 tmp = GNUNET_CRYPTO_ecc_add (edc,
704 gcry_mpi_point_release (s->prod_h_i_b_i);
705 gcry_mpi_point_release (h_i_b_i);
706 s->prod_h_i_b_i = tmp;
709 s->cadet_received_element_count += contained_elements;
710 if ( (s->cadet_received_element_count == max) &&
711 (NULL == s->intersection_op) )
713 /* intersection has finished also on our side, and
714 we got the full set, so we can proceed with the
716 transmit_bobs_cryptodata_message (s);
718 GNUNET_CADET_receive_done (s->cadet->channel);
724 * Callback for set operation results. Called for each element
725 * that needs to be removed from the result set.
727 * @param cls closure with the `struct BobServiceSession`
728 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
729 * @param status what has happened with the set intersection?
732 cb_intersection_element_removed (void *cls,
733 const struct GNUNET_SET_Element *element,
734 enum GNUNET_SET_Status status)
736 struct BobServiceSession *s = cls;
737 struct GNUNET_SCALARPRODUCT_Element *se;
741 case GNUNET_SET_STATUS_OK:
742 /* this element has been removed from the set */
743 se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
745 GNUNET_assert (NULL != se);
746 LOG (GNUNET_ERROR_TYPE_DEBUG,
747 "Removed element with key %s and value %lld\n",
748 GNUNET_h2s (&se->key),
749 (long long) GNUNET_ntohll (se->value));
750 GNUNET_assert (GNUNET_YES ==
751 GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
756 case GNUNET_SET_STATUS_DONE:
757 s->intersection_op = NULL;
758 GNUNET_break (NULL == s->intersection_set);
759 GNUNET_CADET_receive_done (s->cadet->channel);
760 LOG (GNUNET_ERROR_TYPE_DEBUG,
761 "Finished intersection, %d items remain\n",
762 GNUNET_CONTAINER_multihashmap_size (s->intersected_elements));
763 if (s->client_received_element_count ==
764 GNUNET_CONTAINER_multihashmap_size (s->intersected_elements))
766 /* CADET transmission from Alice is also already done,
767 start with our own reply */
768 transmit_bobs_cryptodata_message (s);
771 case GNUNET_SET_STATUS_HALF_DONE:
772 /* unexpected for intersection */
775 case GNUNET_SET_STATUS_FAILURE:
776 /* unhandled status code */
777 LOG (GNUNET_ERROR_TYPE_DEBUG,
778 "Set intersection failed!\n");
779 s->intersection_op = NULL;
780 if (NULL != s->intersection_set)
782 GNUNET_SET_destroy (s->intersection_set);
783 s->intersection_set = NULL;
785 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
786 prepare_client_end_notification (s);
796 * We've paired up a client session with an incoming CADET request.
797 * Initiate set intersection work.
799 * @param s client session to start intersection for
802 start_intersection (struct BobServiceSession *s)
804 struct GNUNET_HashCode set_sid;
806 GNUNET_CRYPTO_hash (&s->session_id,
807 sizeof (struct GNUNET_HashCode),
809 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
810 "Got session with key %s and %u elements, starting intersection.\n",
811 GNUNET_h2s (&s->session_id),
812 (unsigned int) s->total);
815 = GNUNET_SET_prepare (&s->cadet->peer,
818 GNUNET_SET_RESULT_REMOVED,
819 &cb_intersection_element_removed,
822 GNUNET_SET_commit (s->intersection_op,
823 s->intersection_set))
826 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
827 prepare_client_end_notification (s);
830 GNUNET_SET_destroy (s->intersection_set);
831 s->intersection_set = NULL;
836 * Handle a request from Alice to calculate a scalarproduct with us (Bob).
838 * @param cls closure (set from #GNUNET_CADET_connect)
839 * @param channel connection to the other end
840 * @param channel_ctx place to store the `struct CadetIncomingSession *`
841 * @param message the actual message
842 * @return #GNUNET_OK to keep the connection open,
843 * #GNUNET_SYSERR to close it (signal serious error)
846 handle_alices_computation_request (void *cls,
847 struct GNUNET_CADET_Channel *channel,
849 const struct GNUNET_MessageHeader *message)
851 struct CadetIncomingSession *in = *channel_ctx;
852 struct BobServiceSession *s;
853 const struct EccServiceRequestMessage *msg;
855 msg = (const struct EccServiceRequestMessage *) message;
856 if (GNUNET_YES == in->in_map)
859 return GNUNET_SYSERR;
861 if (NULL != find_matching_cadet_session (&msg->session_id))
863 /* not unique, got one like this already */
865 return GNUNET_SYSERR;
867 in->session_id = msg->session_id;
868 GNUNET_assert (GNUNET_YES ==
869 GNUNET_CONTAINER_multihashmap_put (cadet_sessions,
872 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
873 s = find_matching_client_session (&in->session_id);
876 /* no client waiting for this request, wait for client */
879 GNUNET_assert (NULL == s->cadet);
883 if (s->client_received_element_count == s->total)
884 start_intersection (s);
890 * Function called for inbound channels on Bob's end. Does some
891 * preliminary initialization, more happens after we get Alice's first
895 * @param channel new handle to the channel
896 * @param initiator peer that started the channel
898 * @param options unused
899 * @return session associated with the channel
902 cb_channel_incoming (void *cls,
903 struct GNUNET_CADET_Channel *channel,
904 const struct GNUNET_PeerIdentity *initiator,
905 const struct GNUNET_HashCode *port,
906 enum GNUNET_CADET_ChannelOption options)
908 struct CadetIncomingSession *in;
910 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
911 "New incoming channel from peer %s.\n",
912 GNUNET_i2s (initiator));
913 in = GNUNET_new (struct CadetIncomingSession);
914 in->peer = *initiator;
915 in->channel = channel;
916 in->cadet_mq = GNUNET_CADET_mq_create (in->channel);
922 * We're receiving additional set data. Add it to our
923 * set and if we are done, initiate the transaction.
926 * @param client identification of the client
927 * @param message the actual message
930 GSS_handle_bob_client_message_multipart (void *cls,
931 struct GNUNET_SERVER_Client *client,
932 const struct GNUNET_MessageHeader *message)
934 const struct ComputationBobCryptodataMultipartMessage * msg;
935 struct BobServiceSession *s;
936 uint32_t contained_count;
937 const struct GNUNET_SCALARPRODUCT_Element *elements;
940 struct GNUNET_SET_Element set_elem;
941 struct GNUNET_SCALARPRODUCT_Element *elem;
943 s = GNUNET_SERVER_client_get_user_context (client,
944 struct BobServiceSession);
947 /* session needs to already exist */
949 GNUNET_SERVER_receive_done (client,
953 msize = ntohs (message->size);
954 if (msize < sizeof (struct ComputationBobCryptodataMultipartMessage))
957 GNUNET_SERVER_receive_done (client,
961 msg = (const struct ComputationBobCryptodataMultipartMessage *) message;
962 contained_count = ntohl (msg->element_count_contained);
964 if ( (msize != (sizeof (struct ComputationBobCryptodataMultipartMessage) +
965 contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ||
966 (0 == contained_count) ||
967 (UINT16_MAX < contained_count) ||
968 (s->total == s->client_received_element_count) ||
969 (s->total < s->client_received_element_count + contained_count) )
972 GNUNET_SERVER_receive_done (client,
976 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
977 for (i = 0; i < contained_count; i++)
979 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
982 sizeof (struct GNUNET_SCALARPRODUCT_Element));
984 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
987 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
993 set_elem.data = &elem->key;
994 set_elem.size = sizeof (elem->key);
995 set_elem.element_type = 0;
996 GNUNET_SET_add_element (s->intersection_set,
1000 s->client_received_element_count += contained_count;
1001 GNUNET_SERVER_receive_done (client,
1003 if (s->total != s->client_received_element_count)
1008 if (NULL == s->cadet)
1010 /* no Alice waiting for this request, wait for Alice */
1013 start_intersection (s);
1018 * Handler for Bob's a client request message. Bob is in the response
1019 * role, keep the values + session and waiting for a matching session
1020 * or process a waiting request from Alice.
1022 * @param cls closure
1023 * @param client identification of the client
1024 * @param message the actual message
1027 GSS_handle_bob_client_message (void *cls,
1028 struct GNUNET_SERVER_Client *client,
1029 const struct GNUNET_MessageHeader *message)
1031 const struct BobComputationMessage *msg;
1032 struct BobServiceSession *s;
1033 struct CadetIncomingSession *in;
1034 uint32_t contained_count;
1035 uint32_t total_count;
1036 const struct GNUNET_SCALARPRODUCT_Element *elements;
1038 struct GNUNET_SET_Element set_elem;
1039 struct GNUNET_SCALARPRODUCT_Element *elem;
1042 s = GNUNET_SERVER_client_get_user_context (client,
1043 struct BobServiceSession);
1046 /* only one concurrent session per client connection allowed,
1047 simplifies logic a lot... */
1049 GNUNET_SERVER_receive_done (client,
1053 msize = ntohs (message->size);
1054 if (msize < sizeof (struct BobComputationMessage))
1057 GNUNET_SERVER_receive_done (client,
1061 msg = (const struct BobComputationMessage *) message;
1062 total_count = ntohl (msg->element_count_total);
1063 contained_count = ntohl (msg->element_count_contained);
1064 if ( (0 == total_count) ||
1065 (0 == contained_count) ||
1066 (UINT16_MAX < contained_count) ||
1067 (msize != (sizeof (struct BobComputationMessage) +
1068 contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) )
1070 GNUNET_break_op (0);
1071 GNUNET_SERVER_receive_done (client,
1075 if (NULL != find_matching_client_session (&msg->session_key))
1078 GNUNET_SERVER_receive_done (client,
1083 s = GNUNET_new (struct BobServiceSession);
1084 s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
1086 s->client_mq = GNUNET_MQ_queue_for_server_client (client);
1087 s->total = total_count;
1088 s->client_received_element_count = contained_count;
1089 s->session_id = msg->session_key;
1090 s->port = GNUNET_CADET_open_port (my_cadet,
1092 &cb_channel_incoming,
1094 if (NULL == s->port)
1097 GNUNET_SERVER_receive_done (client,
1102 GNUNET_break (GNUNET_YES ==
1103 GNUNET_CONTAINER_multihashmap_put (client_sessions,
1106 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1107 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1108 s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total,
1110 s->intersection_set = GNUNET_SET_create (cfg,
1111 GNUNET_SET_OPERATION_INTERSECTION);
1112 for (i = 0; i < contained_count; i++)
1114 if (0 == GNUNET_ntohll (elements[i].value))
1116 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1117 GNUNET_memcpy (elem,
1119 sizeof (struct GNUNET_SCALARPRODUCT_Element));
1120 if (GNUNET_SYSERR ==
1121 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1124 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1130 set_elem.data = &elem->key;
1131 set_elem.size = sizeof (elem->key);
1132 set_elem.element_type = 0;
1133 GNUNET_SET_add_element (s->intersection_set,
1136 s->used_element_count++;
1138 GNUNET_SERVER_client_set_user_context (client,
1140 GNUNET_SERVER_receive_done (client,
1142 if (s->total != s->client_received_element_count)
1147 in = find_matching_cadet_session (&s->session_id);
1150 /* nothing yet, wait for Alice */
1153 GNUNET_assert (NULL == in->s);
1157 start_intersection (s);
1162 * Task run during shutdown.
1167 shutdown_task (void *cls)
1169 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1170 "Shutting down, initiating cleanup.\n");
1171 // FIXME: we have to cut our connections to CADET first!
1172 if (NULL != my_cadet)
1174 GNUNET_CADET_disconnect (my_cadet);
1179 GNUNET_CRYPTO_ecc_dlog_release (edc);
1182 GNUNET_CONTAINER_multihashmap_destroy (client_sessions);
1183 client_sessions = NULL;
1184 GNUNET_CONTAINER_multihashmap_destroy (cadet_sessions);
1185 cadet_sessions = NULL;
1190 * A client disconnected.
1192 * Remove the associated session(s), release data structures
1193 * and cancel pending outgoing transmissions to the client.
1195 * @param cls closure, NULL
1196 * @param client identification of the client
1199 handle_client_disconnect (void *cls,
1200 struct GNUNET_SERVER_Client *client)
1202 struct BobServiceSession *s;
1206 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1207 "Client disconnected from us.\n");
1208 s = GNUNET_SERVER_client_get_user_context (client,
1209 struct BobServiceSession);
1213 destroy_service_session (s);
1218 * Initialization of the program and message handlers
1220 * @param cls closure
1221 * @param server the initialized server
1222 * @param c configuration to use
1226 struct GNUNET_SERVER_Handle *server,
1227 const struct GNUNET_CONFIGURATION_Handle *c)
1229 static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1230 { &GSS_handle_bob_client_message, NULL,
1231 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB,
1233 { &GSS_handle_bob_client_message_multipart, NULL,
1234 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART_BOB,
1238 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1239 { &handle_alices_computation_request,
1240 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_SESSION_INITIALIZATION,
1241 sizeof (struct EccServiceRequestMessage) },
1242 { &handle_alices_cryptodata_message,
1243 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_ALICE_CRYPTODATA,
1249 /* We don't really do DLOG, so we can setup with very minimal resources */
1250 edc = GNUNET_CRYPTO_ecc_dlog_prepare (4 /* max value */,
1253 GNUNET_SERVER_add_handlers (server,
1255 GNUNET_SERVER_disconnect_notify (server,
1256 &handle_client_disconnect,
1258 client_sessions = GNUNET_CONTAINER_multihashmap_create (128,
1260 cadet_sessions = GNUNET_CONTAINER_multihashmap_create (128,
1262 my_cadet = GNUNET_CADET_connect (cfg, NULL,
1263 &cb_channel_destruction,
1265 if (NULL == my_cadet)
1267 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1268 _("Connect to CADET failed\n"));
1269 GNUNET_SCHEDULER_shutdown ();
1272 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1278 * The main function for the scalarproduct service.
1280 * @param argc number of arguments from the command line
1281 * @param argv command line arguments
1282 * @return 0 ok, 1 on error
1288 return (GNUNET_OK ==
1289 GNUNET_SERVICE_run (argc, argv,
1290 "scalarproduct-bob",
1291 GNUNET_SERVICE_OPTION_NONE,
1292 &run, NULL)) ? 0 : 1;
1295 /* end of gnunet-service-scalarproduct-ecc_bob.c */