2 This file is part of GNUnet.
3 Copyright (C) 2013-2015 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/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 MpiElement *sorted_elements;
112 * Product of the g_i^{b_i}
114 gcry_mpi_point_t prod_g_i_b_i;
117 * Product of the h_i^{b_i}
119 gcry_mpi_point_t prod_h_i_b_i;
122 * Handle for our associated incoming CADET session, or NULL
123 * if we have not gotten one yet.
125 struct CadetIncomingSession *cadet;
128 * How many elements will be supplied in total from the client.
133 * Already transferred elements (received) for multipart
134 * messages from client. Always less than @e total.
136 uint32_t client_received_element_count;
139 * How many elements actually are used for the scalar product.
140 * Size of the arrays in @e r and @e r_prime. Also sometimes
141 * used as an index into the arrays during construction.
143 uint32_t used_element_count;
146 * Counts the number of values received from Alice by us.
147 * Always less than @e used_element_count.
149 uint32_t cadet_received_element_count;
152 * State of this session. In
153 * #GNUNET_SCALARPRODUCT_STATUS_ACTIVE while operation is
154 * ongoing, afterwards in #GNUNET_SCALARPRODUCT_STATUS_SUCCESS or
155 * #GNUNET_SCALARPRODUCT_STATUS_FAILURE.
157 enum GNUNET_SCALARPRODUCT_ResponseStatus status;
160 * Are we already in #destroy_service_session()?
168 * An incoming session from CADET.
170 struct CadetIncomingSession
174 * Associated client session, or NULL.
176 struct BobServiceSession *s;
181 struct GNUNET_CADET_Channel *channel;
184 * Originator's peer identity. (Only for diagnostics.)
186 struct GNUNET_PeerIdentity peer;
189 * (hopefully) unique transaction ID
191 struct GNUNET_HashCode session_id;
194 * The message queue for this channel.
196 struct GNUNET_MQ_Handle *cadet_mq;
199 * Has this CADET session been added to the map yet?
200 * #GNUNET_YES if so, in which case @e session_id is
206 * Are we already in #destroy_cadet_session()?
214 * GNUnet configuration handle
216 static const struct GNUNET_CONFIGURATION_Handle *cfg;
219 * Map of `struct BobServiceSession`, by session keys.
221 static struct GNUNET_CONTAINER_MultiHashMap *client_sessions;
224 * Map of `struct CadetIncomingSession`, by session keys.
226 static struct GNUNET_CONTAINER_MultiHashMap *cadet_sessions;
229 * Handle to the CADET service.
231 static struct GNUNET_CADET_Handle *my_cadet;
234 * Context for DLOG operations on a curve.
236 static struct GNUNET_CRYPTO_EccDlogContext *edc;
241 * Finds a not terminated client session in the respective map based on
244 * @param key the session key we want to search for
245 * @return the matching session, or NULL for none
247 static struct BobServiceSession *
248 find_matching_client_session (const struct GNUNET_HashCode *key)
250 return GNUNET_CONTAINER_multihashmap_get (client_sessions,
256 * Finds a CADET session in the respective map based on session key.
258 * @param key the session key we want to search for
259 * @return the matching session, or NULL for none
261 static struct CadetIncomingSession *
262 find_matching_cadet_session (const struct GNUNET_HashCode *key)
264 return GNUNET_CONTAINER_multihashmap_get (cadet_sessions,
270 * Callback used to free the elements in the map.
273 * @param key key of the element
274 * @param value the value to free
277 free_element_cb (void *cls,
278 const struct GNUNET_HashCode *key,
281 struct GNUNET_SCALARPRODUCT_Element *element = value;
283 GNUNET_free (element);
289 * Destroy session state, we are done with it.
291 * @param session the session to free elements from
294 destroy_cadet_session (struct CadetIncomingSession *s);
298 * Destroy session state, we are done with it.
300 * @param session the session to free elements from
303 destroy_service_session (struct BobServiceSession *s)
305 struct CadetIncomingSession *in;
308 if (GNUNET_YES == s->in_destroy)
310 s->in_destroy = GNUNET_YES;
311 if (NULL != (in = s->cadet))
314 destroy_cadet_session (in);
316 if (NULL != s->client_mq)
318 GNUNET_MQ_destroy (s->client_mq);
321 if (NULL != s->client)
323 GNUNET_SERVER_client_disconnect (s->client);
326 GNUNET_assert (GNUNET_YES ==
327 GNUNET_CONTAINER_multihashmap_remove (client_sessions,
330 if (NULL != s->intersected_elements)
332 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
335 GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements);
336 s->intersected_elements = NULL;
338 if (NULL != s->intersection_op)
340 GNUNET_SET_operation_cancel (s->intersection_op);
341 s->intersection_op = NULL;
343 if (NULL != s->intersection_set)
345 GNUNET_SET_destroy (s->intersection_set);
346 s->intersection_set = NULL;
348 if (NULL != s->sorted_elements)
350 for (i=0;i<s->used_element_count;i++)
351 gcry_mpi_release (s->sorted_elements[i].value);
352 GNUNET_free (s->sorted_elements);
353 s->sorted_elements = NULL;
355 if (NULL != s->prod_g_i_b_i)
357 gcry_mpi_point_release (s->prod_g_i_b_i);
358 s->prod_g_i_b_i = NULL;
360 if (NULL != s->prod_g_i_b_i)
362 gcry_mpi_point_release (s->prod_h_i_b_i);
363 s->prod_h_i_b_i = NULL;
370 * Destroy incoming CADET session state, we are done with it.
372 * @param in the session to free elements from
375 destroy_cadet_session (struct CadetIncomingSession *in)
377 struct BobServiceSession *s;
379 if (GNUNET_YES == in->in_destroy)
381 in->in_destroy = GNUNET_YES;
382 if (NULL != (s = in->s))
385 destroy_service_session (s);
387 if (GNUNET_YES == in->in_map)
389 GNUNET_assert (GNUNET_YES ==
390 GNUNET_CONTAINER_multihashmap_remove (cadet_sessions,
393 in->in_map = GNUNET_NO;
395 if (NULL != in->cadet_mq)
397 GNUNET_MQ_destroy (in->cadet_mq);
400 if (NULL != in->channel)
402 GNUNET_CADET_channel_destroy (in->channel);
410 * Notify the client that the session has succeeded or failed. This
411 * message gets sent to Bob's client if the operation completed or
412 * Alice disconnected.
414 * @param session the associated client session to fail or succeed
417 prepare_client_end_notification (struct BobServiceSession *session)
419 struct ClientResponseMessage *msg;
420 struct GNUNET_MQ_Envelope *e;
422 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
423 "Sending session-end notification with status %d to client for session %s\n",
425 GNUNET_h2s (&session->session_id));
426 e = GNUNET_MQ_msg (msg,
427 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
429 msg->product_length = htonl (0);
430 msg->status = htonl (session->status);
431 GNUNET_MQ_send (session->client_mq,
437 * Function called whenever a channel is destroyed. Should clean up
438 * any associated state.
440 * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
442 * @param cls closure (set from #GNUNET_CADET_connect())
443 * @param channel connection to the other end (henceforth invalid)
444 * @param channel_ctx place where local state associated
445 * with the channel is stored
448 cb_channel_destruction (void *cls,
449 const struct GNUNET_CADET_Channel *channel,
452 struct CadetIncomingSession *in = channel_ctx;
453 struct BobServiceSession *s;
455 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
456 "Peer disconnected, terminating session %s with peer %s\n",
457 GNUNET_h2s (&in->session_id),
458 GNUNET_i2s (&in->peer));
459 if (NULL != in->cadet_mq)
461 GNUNET_MQ_destroy (in->cadet_mq);
465 if (NULL != (s = in->s))
467 if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
469 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
470 prepare_client_end_notification (s);
473 destroy_cadet_session (in);
478 * MQ finished giving our last message to CADET, now notify
479 * the client that we are finished.
482 bob_cadet_done_cb (void *cls)
484 struct BobServiceSession *session = cls;
486 session->status = GNUNET_SCALARPRODUCT_STATUS_SUCCESS;
487 prepare_client_end_notification (session);
492 * Bob generates the response message to be sent to Alice.
494 * @param s the associated requesting session with Alice
497 transmit_bobs_cryptodata_message (struct BobServiceSession *s)
499 struct EccBobCryptodataMessage *msg;
500 struct GNUNET_MQ_Envelope *e;
502 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
503 "Sending response to Alice\n");
504 e = GNUNET_MQ_msg (msg,
505 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_BOB_CRYPTODATA);
506 msg->contained_element_count = htonl (2);
507 if (NULL != s->prod_g_i_b_i)
508 GNUNET_CRYPTO_ecc_point_to_bin (edc,
511 if (NULL != s->prod_h_i_b_i)
512 GNUNET_CRYPTO_ecc_point_to_bin (edc,
515 GNUNET_MQ_notify_sent (e,
518 GNUNET_MQ_send (s->cadet->cadet_mq,
524 * Iterator to copy over messages from the hash map
525 * into an array for sorting.
527 * @param cls the `struct BobServiceSession *`
528 * @param key the key (unused)
529 * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
530 * TODO: code duplication with Alice!
533 copy_element_cb (void *cls,
534 const struct GNUNET_HashCode *key,
537 struct BobServiceSession *s = cls;
538 struct GNUNET_SCALARPRODUCT_Element *e = value;
542 mval = gcry_mpi_new (0);
543 val = (int64_t) GNUNET_ntohll (e->value);
545 gcry_mpi_sub_ui (mval, mval, -val);
547 gcry_mpi_add_ui (mval, mval, val);
548 s->sorted_elements [s->used_element_count].value = mval;
549 s->sorted_elements [s->used_element_count].key = &e->key;
550 s->used_element_count++;
556 * Compare two `struct MpiValue`s by key for sorting.
558 * @param a pointer to first `struct MpiValue *`
559 * @param b pointer to first `struct MpiValue *`
560 * @return -1 for a < b, 0 for a=b, 1 for a > b.
561 * TODO: code duplication with Alice!
564 element_cmp (const void *a,
567 const struct MpiElement *ma = a;
568 const struct MpiElement *mb = b;
570 return GNUNET_CRYPTO_hash_cmp (ma->key,
576 * Handle a multipart-chunk of a request from another service to
577 * calculate a scalarproduct with us.
579 * @param cls closure (set from #GNUNET_CADET_connect)
580 * @param channel connection to the other end
581 * @param channel_ctx place to store local state associated with the @a channel
582 * @param message the actual message
583 * @return #GNUNET_OK to keep the connection open,
584 * #GNUNET_SYSERR to close it (signal serious error)
587 handle_alices_cryptodata_message (void *cls,
588 struct GNUNET_CADET_Channel *channel,
590 const struct GNUNET_MessageHeader *message)
592 struct CadetIncomingSession *in = *channel_ctx;
593 struct BobServiceSession *s;
594 const struct EccAliceCryptodataMessage *msg;
595 const struct GNUNET_CRYPTO_EccPoint *payload;
596 uint32_t contained_elements;
601 const struct MpiElement *b_i;
602 gcry_mpi_point_t tmp;
603 gcry_mpi_point_t g_i;
604 gcry_mpi_point_t h_i;
605 gcry_mpi_point_t g_i_b_i;
606 gcry_mpi_point_t h_i_b_i;
612 return GNUNET_SYSERR;
618 return GNUNET_SYSERR;
620 /* sort our vector for the computation */
621 if (NULL == s->sorted_elements)
624 = GNUNET_malloc (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements) *
625 sizeof (struct MpiElement));
626 s->used_element_count = 0;
627 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
630 qsort (s->sorted_elements,
631 s->used_element_count,
632 sizeof (struct MpiElement),
637 msize = ntohs (message->size);
638 if (msize <= sizeof (struct EccAliceCryptodataMessage))
641 return GNUNET_SYSERR;
643 msg = (const struct EccAliceCryptodataMessage *) message;
644 contained_elements = ntohl (msg->contained_element_count);
645 /* Our intersection may still be ongoing, but this is nevertheless
646 an upper bound on the required array size */
647 max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements);
648 msg_length = sizeof (struct EccAliceCryptodataMessage)
649 + contained_elements * sizeof (struct GNUNET_CRYPTO_EccPoint) * 2;
650 if ( (msize != msg_length) ||
651 (0 == contained_elements) ||
652 (contained_elements > UINT16_MAX) ||
653 (max < contained_elements + s->cadet_received_element_count) )
656 return GNUNET_SYSERR;
658 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
659 "Received %u crypto values from Alice\n",
660 (unsigned int) contained_elements);
661 payload = (const struct GNUNET_CRYPTO_EccPoint *) &msg[1];
663 for (i=0;i<contained_elements;i++)
665 b_i = &s->sorted_elements[i + s->cadet_received_element_count];
666 g_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
668 g_i_b_i = GNUNET_CRYPTO_ecc_pmul_mpi (edc,
671 gcry_mpi_point_release (g_i);
672 h_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
673 &payload[i * 2 + 1]);
674 h_i_b_i = GNUNET_CRYPTO_ecc_pmul_mpi (edc,
677 gcry_mpi_point_release (h_i);
678 if (0 == i + s->cadet_received_element_count)
680 /* first iteration, nothing to add */
681 s->prod_g_i_b_i = g_i_b_i;
682 s->prod_h_i_b_i = h_i_b_i;
686 /* further iterations, cummulate resulting value */
687 tmp = GNUNET_CRYPTO_ecc_add (edc,
690 gcry_mpi_point_release (s->prod_g_i_b_i);
691 gcry_mpi_point_release (g_i_b_i);
692 s->prod_g_i_b_i = tmp;
693 tmp = GNUNET_CRYPTO_ecc_add (edc,
696 gcry_mpi_point_release (s->prod_h_i_b_i);
697 gcry_mpi_point_release (h_i_b_i);
698 s->prod_h_i_b_i = tmp;
701 s->cadet_received_element_count += contained_elements;
702 if ( (s->cadet_received_element_count == max) &&
703 (NULL == s->intersection_op) )
705 /* intersection has finished also on our side, and
706 we got the full set, so we can proceed with the
708 transmit_bobs_cryptodata_message (s);
710 GNUNET_CADET_receive_done (s->cadet->channel);
716 * Callback for set operation results. Called for each element
717 * that needs to be removed from the result set.
719 * @param cls closure with the `struct BobServiceSession`
720 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
721 * @param status what has happened with the set intersection?
724 cb_intersection_element_removed (void *cls,
725 const struct GNUNET_SET_Element *element,
726 enum GNUNET_SET_Status status)
728 struct BobServiceSession *s = cls;
729 struct GNUNET_SCALARPRODUCT_Element *se;
733 case GNUNET_SET_STATUS_OK:
734 /* this element has been removed from the set */
735 se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
737 GNUNET_assert (NULL != se);
738 LOG (GNUNET_ERROR_TYPE_DEBUG,
739 "Removed element with key %s and value %lld\n",
740 GNUNET_h2s (&se->key),
741 (long long) GNUNET_ntohll (se->value));
742 GNUNET_assert (GNUNET_YES ==
743 GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
748 case GNUNET_SET_STATUS_DONE:
749 s->intersection_op = NULL;
750 GNUNET_break (NULL == s->intersection_set);
751 GNUNET_CADET_receive_done (s->cadet->channel);
752 LOG (GNUNET_ERROR_TYPE_DEBUG,
753 "Finished intersection, %d items remain\n",
754 GNUNET_CONTAINER_multihashmap_size (s->intersected_elements));
755 if (s->client_received_element_count ==
756 GNUNET_CONTAINER_multihashmap_size (s->intersected_elements))
758 /* CADET transmission from Alice is also already done,
759 start with our own reply */
760 transmit_bobs_cryptodata_message (s);
763 case GNUNET_SET_STATUS_HALF_DONE:
764 /* unexpected for intersection */
767 case GNUNET_SET_STATUS_FAILURE:
768 /* unhandled status code */
769 LOG (GNUNET_ERROR_TYPE_DEBUG,
770 "Set intersection failed!\n");
771 s->intersection_op = NULL;
772 if (NULL != s->intersection_set)
774 GNUNET_SET_destroy (s->intersection_set);
775 s->intersection_set = NULL;
777 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
778 prepare_client_end_notification (s);
788 * We've paired up a client session with an incoming CADET request.
789 * Initiate set intersection work.
791 * @param s client session to start intersection for
794 start_intersection (struct BobServiceSession *s)
796 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
797 "Got session with key %s and %u elements, starting intersection.\n",
798 GNUNET_h2s (&s->session_id),
799 (unsigned int) s->total);
802 = GNUNET_SET_prepare (&s->cadet->peer,
805 GNUNET_SET_RESULT_REMOVED,
806 &cb_intersection_element_removed,
809 GNUNET_SET_commit (s->intersection_op,
810 s->intersection_set))
813 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
814 prepare_client_end_notification (s);
817 GNUNET_SET_destroy (s->intersection_set);
818 s->intersection_set = NULL;
823 * Handle a request from Alice to calculate a scalarproduct with us (Bob).
825 * @param cls closure (set from #GNUNET_CADET_connect)
826 * @param channel connection to the other end
827 * @param channel_ctx place to store the `struct CadetIncomingSession *`
828 * @param message the actual message
829 * @return #GNUNET_OK to keep the connection open,
830 * #GNUNET_SYSERR to close it (signal serious error)
833 handle_alices_computation_request (void *cls,
834 struct GNUNET_CADET_Channel *channel,
836 const struct GNUNET_MessageHeader *message)
838 struct CadetIncomingSession *in = *channel_ctx;
839 struct BobServiceSession *s;
840 const struct EccServiceRequestMessage *msg;
842 msg = (const struct EccServiceRequestMessage *) message;
843 if (GNUNET_YES == in->in_map)
846 return GNUNET_SYSERR;
848 if (NULL != find_matching_cadet_session (&msg->session_id))
850 /* not unique, got one like this already */
852 return GNUNET_SYSERR;
854 in->session_id = msg->session_id;
855 GNUNET_assert (GNUNET_YES ==
856 GNUNET_CONTAINER_multihashmap_put (cadet_sessions,
859 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
860 s = find_matching_client_session (&in->session_id);
863 /* no client waiting for this request, wait for client */
866 GNUNET_assert (NULL == s->cadet);
870 if (s->client_received_element_count == s->total)
871 start_intersection (s);
877 * Function called for inbound channels on Bob's end. Does some
878 * preliminary initialization, more happens after we get Alice's first
882 * @param channel new handle to the channel
883 * @param initiator peer that started the channel
885 * @param options unused
886 * @return session associated with the channel
889 cb_channel_incoming (void *cls,
890 struct GNUNET_CADET_Channel *channel,
891 const struct GNUNET_PeerIdentity *initiator,
893 enum GNUNET_CADET_ChannelOption options)
895 struct CadetIncomingSession *in;
897 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
898 "New incoming channel from peer %s.\n",
899 GNUNET_i2s (initiator));
900 in = GNUNET_new (struct CadetIncomingSession);
901 in->peer = *initiator;
902 in->channel = channel;
903 in->cadet_mq = GNUNET_CADET_mq_create (in->channel);
909 * We're receiving additional set data. Add it to our
910 * set and if we are done, initiate the transaction.
913 * @param client identification of the client
914 * @param message the actual message
917 GSS_handle_bob_client_message_multipart (void *cls,
918 struct GNUNET_SERVER_Client *client,
919 const struct GNUNET_MessageHeader *message)
921 const struct ComputationBobCryptodataMultipartMessage * msg;
922 struct BobServiceSession *s;
923 uint32_t contained_count;
924 const struct GNUNET_SCALARPRODUCT_Element *elements;
927 struct GNUNET_SET_Element set_elem;
928 struct GNUNET_SCALARPRODUCT_Element *elem;
930 s = GNUNET_SERVER_client_get_user_context (client,
931 struct BobServiceSession);
934 /* session needs to already exist */
936 GNUNET_SERVER_receive_done (client,
940 msize = ntohs (message->size);
941 if (msize < sizeof (struct ComputationBobCryptodataMultipartMessage))
944 GNUNET_SERVER_receive_done (client,
948 msg = (const struct ComputationBobCryptodataMultipartMessage *) message;
949 contained_count = ntohl (msg->element_count_contained);
951 if ( (msize != (sizeof (struct ComputationBobCryptodataMultipartMessage) +
952 contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ||
953 (0 == contained_count) ||
954 (UINT16_MAX < contained_count) ||
955 (s->total == s->client_received_element_count) ||
956 (s->total < s->client_received_element_count + contained_count) )
959 GNUNET_SERVER_receive_done (client,
963 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
964 for (i = 0; i < contained_count; i++)
966 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
969 sizeof (struct GNUNET_SCALARPRODUCT_Element));
971 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
974 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
980 set_elem.data = &elem->key;
981 set_elem.size = sizeof (elem->key);
982 set_elem.element_type = 0;
983 GNUNET_SET_add_element (s->intersection_set,
987 s->client_received_element_count += contained_count;
988 GNUNET_SERVER_receive_done (client,
990 if (s->total != s->client_received_element_count)
995 if (NULL == s->cadet)
997 /* no Alice waiting for this request, wait for Alice */
1000 start_intersection (s);
1005 * Handler for Bob's a client request message. Bob is in the response
1006 * role, keep the values + session and waiting for a matching session
1007 * or process a waiting request from Alice.
1009 * @param cls closure
1010 * @param client identification of the client
1011 * @param message the actual message
1014 GSS_handle_bob_client_message (void *cls,
1015 struct GNUNET_SERVER_Client *client,
1016 const struct GNUNET_MessageHeader *message)
1018 const struct BobComputationMessage *msg;
1019 struct BobServiceSession *s;
1020 struct CadetIncomingSession *in;
1021 uint32_t contained_count;
1022 uint32_t total_count;
1023 const struct GNUNET_SCALARPRODUCT_Element *elements;
1025 struct GNUNET_SET_Element set_elem;
1026 struct GNUNET_SCALARPRODUCT_Element *elem;
1029 s = GNUNET_SERVER_client_get_user_context (client,
1030 struct BobServiceSession);
1033 /* only one concurrent session per client connection allowed,
1034 simplifies logic a lot... */
1036 GNUNET_SERVER_receive_done (client,
1040 msize = ntohs (message->size);
1041 if (msize < sizeof (struct BobComputationMessage))
1044 GNUNET_SERVER_receive_done (client,
1048 msg = (const struct BobComputationMessage *) message;
1049 total_count = ntohl (msg->element_count_total);
1050 contained_count = ntohl (msg->element_count_contained);
1051 if ( (0 == total_count) ||
1052 (0 == contained_count) ||
1053 (UINT16_MAX < contained_count) ||
1054 (msize != (sizeof (struct BobComputationMessage) +
1055 contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) )
1057 GNUNET_break_op (0);
1058 GNUNET_SERVER_receive_done (client,
1062 if (NULL != find_matching_client_session (&msg->session_key))
1065 GNUNET_SERVER_receive_done (client,
1070 s = GNUNET_new (struct BobServiceSession);
1071 s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
1073 s->client_mq = GNUNET_MQ_queue_for_server_client (client);
1074 s->total = total_count;
1075 s->client_received_element_count = contained_count;
1076 s->session_id = msg->session_key;
1077 GNUNET_break (GNUNET_YES ==
1078 GNUNET_CONTAINER_multihashmap_put (client_sessions,
1081 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1082 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1083 s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total,
1085 s->intersection_set = GNUNET_SET_create (cfg,
1086 GNUNET_SET_OPERATION_INTERSECTION);
1087 for (i = 0; i < contained_count; i++)
1089 if (0 == GNUNET_ntohll (elements[i].value))
1091 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1094 sizeof (struct GNUNET_SCALARPRODUCT_Element));
1095 if (GNUNET_SYSERR ==
1096 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1099 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1105 set_elem.data = &elem->key;
1106 set_elem.size = sizeof (elem->key);
1107 set_elem.element_type = 0;
1108 GNUNET_SET_add_element (s->intersection_set,
1111 s->used_element_count++;
1113 GNUNET_SERVER_client_set_user_context (client,
1115 GNUNET_SERVER_receive_done (client,
1117 if (s->total != s->client_received_element_count)
1122 in = find_matching_cadet_session (&s->session_id);
1125 /* nothing yet, wait for Alice */
1128 GNUNET_assert (NULL == in->s);
1132 start_intersection (s);
1137 * Task run during shutdown.
1143 shutdown_task (void *cls,
1144 const struct GNUNET_SCHEDULER_TaskContext *tc)
1146 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1147 "Shutting down, initiating cleanup.\n");
1148 // FIXME: we have to cut our connections to CADET first!
1149 if (NULL != my_cadet)
1151 GNUNET_CADET_disconnect (my_cadet);
1156 GNUNET_CRYPTO_ecc_dlog_release (edc);
1159 GNUNET_CONTAINER_multihashmap_destroy (client_sessions);
1160 client_sessions = NULL;
1161 GNUNET_CONTAINER_multihashmap_destroy (cadet_sessions);
1162 cadet_sessions = NULL;
1167 * A client disconnected.
1169 * Remove the associated session(s), release data structures
1170 * and cancel pending outgoing transmissions to the client.
1172 * @param cls closure, NULL
1173 * @param client identification of the client
1176 handle_client_disconnect (void *cls,
1177 struct GNUNET_SERVER_Client *client)
1179 struct BobServiceSession *s;
1183 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1184 "Client disconnected from us.\n",
1186 s = GNUNET_SERVER_client_get_user_context (client,
1187 struct BobServiceSession);
1191 destroy_service_session (s);
1196 * Initialization of the program and message handlers
1198 * @param cls closure
1199 * @param server the initialized server
1200 * @param c configuration to use
1204 struct GNUNET_SERVER_Handle *server,
1205 const struct GNUNET_CONFIGURATION_Handle *c)
1207 static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1208 { &GSS_handle_bob_client_message, NULL,
1209 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB,
1211 { &GSS_handle_bob_client_message_multipart, NULL,
1212 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART_BOB,
1216 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1217 { &handle_alices_computation_request,
1218 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_SESSION_INITIALIZATION,
1219 sizeof (struct EccServiceRequestMessage) },
1220 { &handle_alices_cryptodata_message,
1221 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_ALICE_CRYPTODATA,
1225 static const uint32_t ports[] = {
1226 GNUNET_APPLICATION_TYPE_SCALARPRODUCT_ECC,
1231 /* We don't really do DLOG, so we can setup with very minimal resources */
1232 edc = GNUNET_CRYPTO_ecc_dlog_prepare (4 /* max value */,
1235 GNUNET_SERVER_add_handlers (server,
1237 GNUNET_SERVER_disconnect_notify (server,
1238 &handle_client_disconnect,
1240 client_sessions = GNUNET_CONTAINER_multihashmap_create (128,
1242 cadet_sessions = GNUNET_CONTAINER_multihashmap_create (128,
1244 my_cadet = GNUNET_CADET_connect (cfg, NULL,
1245 &cb_channel_incoming,
1246 &cb_channel_destruction,
1249 if (NULL == my_cadet)
1251 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1252 _("Connect to CADET failed\n"));
1253 GNUNET_SCHEDULER_shutdown ();
1256 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1263 * The main function for the scalarproduct service.
1265 * @param argc number of arguments from the command line
1266 * @param argv command line arguments
1267 * @return 0 ok, 1 on error
1273 return (GNUNET_OK ==
1274 GNUNET_SERVICE_run (argc, argv,
1275 "scalarproduct-bob",
1276 GNUNET_SERVICE_OPTION_NONE,
1277 &run, NULL)) ? 0 : 1;
1280 /* end of gnunet-service-scalarproduct-ecc_bob.c */