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 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_h_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 if (NULL == session->client_mq)
423 return; /* no client left to be notified */
424 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
425 "Sending session-end notification with status %d to client for session %s\n",
427 GNUNET_h2s (&session->session_id));
428 e = GNUNET_MQ_msg (msg,
429 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
431 msg->product_length = htonl (0);
432 msg->status = htonl (session->status);
433 GNUNET_MQ_send (session->client_mq,
439 * Function called whenever a channel is destroyed. Should clean up
440 * any associated state.
442 * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
444 * @param cls closure (set from #GNUNET_CADET_connect())
445 * @param channel connection to the other end (henceforth invalid)
446 * @param channel_ctx place where local state associated
447 * with the channel is stored
450 cb_channel_destruction (void *cls,
451 const struct GNUNET_CADET_Channel *channel,
454 struct CadetIncomingSession *in = channel_ctx;
455 struct BobServiceSession *s;
457 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
458 "Peer disconnected, terminating session %s with peer %s\n",
459 GNUNET_h2s (&in->session_id),
460 GNUNET_i2s (&in->peer));
461 if (NULL != in->cadet_mq)
463 GNUNET_MQ_destroy (in->cadet_mq);
467 if (NULL != (s = in->s))
469 if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
471 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
472 prepare_client_end_notification (s);
475 destroy_cadet_session (in);
480 * MQ finished giving our last message to CADET, now notify
481 * the client that we are finished.
484 bob_cadet_done_cb (void *cls)
486 struct BobServiceSession *session = cls;
488 session->status = GNUNET_SCALARPRODUCT_STATUS_SUCCESS;
489 prepare_client_end_notification (session);
494 * Bob generates the response message to be sent to Alice.
496 * @param s the associated requesting session with Alice
499 transmit_bobs_cryptodata_message (struct BobServiceSession *s)
501 struct EccBobCryptodataMessage *msg;
502 struct GNUNET_MQ_Envelope *e;
504 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
505 "Sending response to Alice\n");
506 e = GNUNET_MQ_msg (msg,
507 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_BOB_CRYPTODATA);
508 msg->contained_element_count = htonl (2);
509 if (NULL != s->prod_g_i_b_i)
510 GNUNET_CRYPTO_ecc_point_to_bin (edc,
513 if (NULL != s->prod_h_i_b_i)
514 GNUNET_CRYPTO_ecc_point_to_bin (edc,
517 GNUNET_MQ_notify_sent (e,
520 GNUNET_MQ_send (s->cadet->cadet_mq,
526 * Iterator to copy over messages from the hash map
527 * into an array for sorting.
529 * @param cls the `struct BobServiceSession *`
530 * @param key the key (unused)
531 * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
532 * TODO: code duplication with Alice!
535 copy_element_cb (void *cls,
536 const struct GNUNET_HashCode *key,
539 struct BobServiceSession *s = cls;
540 struct GNUNET_SCALARPRODUCT_Element *e = value;
544 mval = gcry_mpi_new (0);
545 val = (int64_t) GNUNET_ntohll (e->value);
547 gcry_mpi_sub_ui (mval, mval, -val);
549 gcry_mpi_add_ui (mval, mval, val);
550 s->sorted_elements [s->used_element_count].value = mval;
551 s->sorted_elements [s->used_element_count].key = &e->key;
552 s->used_element_count++;
558 * Compare two `struct MpiValue`s by key for sorting.
560 * @param a pointer to first `struct MpiValue *`
561 * @param b pointer to first `struct MpiValue *`
562 * @return -1 for a < b, 0 for a=b, 1 for a > b.
563 * TODO: code duplication with Alice!
566 element_cmp (const void *a,
569 const struct MpiElement *ma = a;
570 const struct MpiElement *mb = b;
572 return GNUNET_CRYPTO_hash_cmp (ma->key,
578 * Handle a multipart-chunk of a request from another service to
579 * calculate a scalarproduct with us.
581 * @param cls closure (set from #GNUNET_CADET_connect)
582 * @param channel connection to the other end
583 * @param channel_ctx place to store local state associated with the @a channel
584 * @param message the actual message
585 * @return #GNUNET_OK to keep the connection open,
586 * #GNUNET_SYSERR to close it (signal serious error)
589 handle_alices_cryptodata_message (void *cls,
590 struct GNUNET_CADET_Channel *channel,
592 const struct GNUNET_MessageHeader *message)
594 struct CadetIncomingSession *in = *channel_ctx;
595 struct BobServiceSession *s;
596 const struct EccAliceCryptodataMessage *msg;
597 const struct GNUNET_CRYPTO_EccPoint *payload;
598 uint32_t contained_elements;
603 const struct MpiElement *b_i;
604 gcry_mpi_point_t tmp;
605 gcry_mpi_point_t g_i;
606 gcry_mpi_point_t h_i;
607 gcry_mpi_point_t g_i_b_i;
608 gcry_mpi_point_t h_i_b_i;
614 return GNUNET_SYSERR;
620 return GNUNET_SYSERR;
622 /* sort our vector for the computation */
623 if (NULL == s->sorted_elements)
626 = GNUNET_malloc (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements) *
627 sizeof (struct MpiElement));
628 s->used_element_count = 0;
629 GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
632 qsort (s->sorted_elements,
633 s->used_element_count,
634 sizeof (struct MpiElement),
639 msize = ntohs (message->size);
640 if (msize <= sizeof (struct EccAliceCryptodataMessage))
643 return GNUNET_SYSERR;
645 msg = (const struct EccAliceCryptodataMessage *) message;
646 contained_elements = ntohl (msg->contained_element_count);
647 /* Our intersection may still be ongoing, but this is nevertheless
648 an upper bound on the required array size */
649 max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements);
650 msg_length = sizeof (struct EccAliceCryptodataMessage)
651 + contained_elements * sizeof (struct GNUNET_CRYPTO_EccPoint) * 2;
652 if ( (msize != msg_length) ||
653 (0 == contained_elements) ||
654 (contained_elements > UINT16_MAX) ||
655 (max < contained_elements + s->cadet_received_element_count) )
658 return GNUNET_SYSERR;
660 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
661 "Received %u crypto values from Alice\n",
662 (unsigned int) contained_elements);
663 payload = (const struct GNUNET_CRYPTO_EccPoint *) &msg[1];
665 for (i=0;i<contained_elements;i++)
667 b_i = &s->sorted_elements[i + s->cadet_received_element_count];
668 g_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
670 g_i_b_i = GNUNET_CRYPTO_ecc_pmul_mpi (edc,
673 gcry_mpi_point_release (g_i);
674 h_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
675 &payload[i * 2 + 1]);
676 h_i_b_i = GNUNET_CRYPTO_ecc_pmul_mpi (edc,
679 gcry_mpi_point_release (h_i);
680 if (0 == i + s->cadet_received_element_count)
682 /* first iteration, nothing to add */
683 s->prod_g_i_b_i = g_i_b_i;
684 s->prod_h_i_b_i = h_i_b_i;
688 /* further iterations, cummulate resulting value */
689 tmp = GNUNET_CRYPTO_ecc_add (edc,
692 gcry_mpi_point_release (s->prod_g_i_b_i);
693 gcry_mpi_point_release (g_i_b_i);
694 s->prod_g_i_b_i = tmp;
695 tmp = GNUNET_CRYPTO_ecc_add (edc,
698 gcry_mpi_point_release (s->prod_h_i_b_i);
699 gcry_mpi_point_release (h_i_b_i);
700 s->prod_h_i_b_i = tmp;
703 s->cadet_received_element_count += contained_elements;
704 if ( (s->cadet_received_element_count == max) &&
705 (NULL == s->intersection_op) )
707 /* intersection has finished also on our side, and
708 we got the full set, so we can proceed with the
710 transmit_bobs_cryptodata_message (s);
712 GNUNET_CADET_receive_done (s->cadet->channel);
718 * Callback for set operation results. Called for each element
719 * that needs to be removed from the result set.
721 * @param cls closure with the `struct BobServiceSession`
722 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
723 * @param status what has happened with the set intersection?
726 cb_intersection_element_removed (void *cls,
727 const struct GNUNET_SET_Element *element,
728 enum GNUNET_SET_Status status)
730 struct BobServiceSession *s = cls;
731 struct GNUNET_SCALARPRODUCT_Element *se;
735 case GNUNET_SET_STATUS_OK:
736 /* this element has been removed from the set */
737 se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
739 GNUNET_assert (NULL != se);
740 LOG (GNUNET_ERROR_TYPE_DEBUG,
741 "Removed element with key %s and value %lld\n",
742 GNUNET_h2s (&se->key),
743 (long long) GNUNET_ntohll (se->value));
744 GNUNET_assert (GNUNET_YES ==
745 GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
750 case GNUNET_SET_STATUS_DONE:
751 s->intersection_op = NULL;
752 GNUNET_break (NULL == s->intersection_set);
753 GNUNET_CADET_receive_done (s->cadet->channel);
754 LOG (GNUNET_ERROR_TYPE_DEBUG,
755 "Finished intersection, %d items remain\n",
756 GNUNET_CONTAINER_multihashmap_size (s->intersected_elements));
757 if (s->client_received_element_count ==
758 GNUNET_CONTAINER_multihashmap_size (s->intersected_elements))
760 /* CADET transmission from Alice is also already done,
761 start with our own reply */
762 transmit_bobs_cryptodata_message (s);
765 case GNUNET_SET_STATUS_HALF_DONE:
766 /* unexpected for intersection */
769 case GNUNET_SET_STATUS_FAILURE:
770 /* unhandled status code */
771 LOG (GNUNET_ERROR_TYPE_DEBUG,
772 "Set intersection failed!\n");
773 s->intersection_op = NULL;
774 if (NULL != s->intersection_set)
776 GNUNET_SET_destroy (s->intersection_set);
777 s->intersection_set = NULL;
779 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
780 prepare_client_end_notification (s);
790 * We've paired up a client session with an incoming CADET request.
791 * Initiate set intersection work.
793 * @param s client session to start intersection for
796 start_intersection (struct BobServiceSession *s)
798 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
799 "Got session with key %s and %u elements, starting intersection.\n",
800 GNUNET_h2s (&s->session_id),
801 (unsigned int) s->total);
804 = GNUNET_SET_prepare (&s->cadet->peer,
807 GNUNET_SET_RESULT_REMOVED,
808 &cb_intersection_element_removed,
811 GNUNET_SET_commit (s->intersection_op,
812 s->intersection_set))
815 s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
816 prepare_client_end_notification (s);
819 GNUNET_SET_destroy (s->intersection_set);
820 s->intersection_set = NULL;
825 * Handle a request from Alice to calculate a scalarproduct with us (Bob).
827 * @param cls closure (set from #GNUNET_CADET_connect)
828 * @param channel connection to the other end
829 * @param channel_ctx place to store the `struct CadetIncomingSession *`
830 * @param message the actual message
831 * @return #GNUNET_OK to keep the connection open,
832 * #GNUNET_SYSERR to close it (signal serious error)
835 handle_alices_computation_request (void *cls,
836 struct GNUNET_CADET_Channel *channel,
838 const struct GNUNET_MessageHeader *message)
840 struct CadetIncomingSession *in = *channel_ctx;
841 struct BobServiceSession *s;
842 const struct EccServiceRequestMessage *msg;
844 msg = (const struct EccServiceRequestMessage *) message;
845 if (GNUNET_YES == in->in_map)
848 return GNUNET_SYSERR;
850 if (NULL != find_matching_cadet_session (&msg->session_id))
852 /* not unique, got one like this already */
854 return GNUNET_SYSERR;
856 in->session_id = msg->session_id;
857 GNUNET_assert (GNUNET_YES ==
858 GNUNET_CONTAINER_multihashmap_put (cadet_sessions,
861 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
862 s = find_matching_client_session (&in->session_id);
865 /* no client waiting for this request, wait for client */
868 GNUNET_assert (NULL == s->cadet);
872 if (s->client_received_element_count == s->total)
873 start_intersection (s);
879 * Function called for inbound channels on Bob's end. Does some
880 * preliminary initialization, more happens after we get Alice's first
884 * @param channel new handle to the channel
885 * @param initiator peer that started the channel
887 * @param options unused
888 * @return session associated with the channel
891 cb_channel_incoming (void *cls,
892 struct GNUNET_CADET_Channel *channel,
893 const struct GNUNET_PeerIdentity *initiator,
895 enum GNUNET_CADET_ChannelOption options)
897 struct CadetIncomingSession *in;
899 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
900 "New incoming channel from peer %s.\n",
901 GNUNET_i2s (initiator));
902 in = GNUNET_new (struct CadetIncomingSession);
903 in->peer = *initiator;
904 in->channel = channel;
905 in->cadet_mq = GNUNET_CADET_mq_create (in->channel);
911 * We're receiving additional set data. Add it to our
912 * set and if we are done, initiate the transaction.
915 * @param client identification of the client
916 * @param message the actual message
919 GSS_handle_bob_client_message_multipart (void *cls,
920 struct GNUNET_SERVER_Client *client,
921 const struct GNUNET_MessageHeader *message)
923 const struct ComputationBobCryptodataMultipartMessage * msg;
924 struct BobServiceSession *s;
925 uint32_t contained_count;
926 const struct GNUNET_SCALARPRODUCT_Element *elements;
929 struct GNUNET_SET_Element set_elem;
930 struct GNUNET_SCALARPRODUCT_Element *elem;
932 s = GNUNET_SERVER_client_get_user_context (client,
933 struct BobServiceSession);
936 /* session needs to already exist */
938 GNUNET_SERVER_receive_done (client,
942 msize = ntohs (message->size);
943 if (msize < sizeof (struct ComputationBobCryptodataMultipartMessage))
946 GNUNET_SERVER_receive_done (client,
950 msg = (const struct ComputationBobCryptodataMultipartMessage *) message;
951 contained_count = ntohl (msg->element_count_contained);
953 if ( (msize != (sizeof (struct ComputationBobCryptodataMultipartMessage) +
954 contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ||
955 (0 == contained_count) ||
956 (UINT16_MAX < contained_count) ||
957 (s->total == s->client_received_element_count) ||
958 (s->total < s->client_received_element_count + contained_count) )
961 GNUNET_SERVER_receive_done (client,
965 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
966 for (i = 0; i < contained_count; i++)
968 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
971 sizeof (struct GNUNET_SCALARPRODUCT_Element));
973 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
976 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
982 set_elem.data = &elem->key;
983 set_elem.size = sizeof (elem->key);
984 set_elem.element_type = 0;
985 GNUNET_SET_add_element (s->intersection_set,
989 s->client_received_element_count += contained_count;
990 GNUNET_SERVER_receive_done (client,
992 if (s->total != s->client_received_element_count)
997 if (NULL == s->cadet)
999 /* no Alice waiting for this request, wait for Alice */
1002 start_intersection (s);
1007 * Handler for Bob's a client request message. Bob is in the response
1008 * role, keep the values + session and waiting for a matching session
1009 * or process a waiting request from Alice.
1011 * @param cls closure
1012 * @param client identification of the client
1013 * @param message the actual message
1016 GSS_handle_bob_client_message (void *cls,
1017 struct GNUNET_SERVER_Client *client,
1018 const struct GNUNET_MessageHeader *message)
1020 const struct BobComputationMessage *msg;
1021 struct BobServiceSession *s;
1022 struct CadetIncomingSession *in;
1023 uint32_t contained_count;
1024 uint32_t total_count;
1025 const struct GNUNET_SCALARPRODUCT_Element *elements;
1027 struct GNUNET_SET_Element set_elem;
1028 struct GNUNET_SCALARPRODUCT_Element *elem;
1031 s = GNUNET_SERVER_client_get_user_context (client,
1032 struct BobServiceSession);
1035 /* only one concurrent session per client connection allowed,
1036 simplifies logic a lot... */
1038 GNUNET_SERVER_receive_done (client,
1042 msize = ntohs (message->size);
1043 if (msize < sizeof (struct BobComputationMessage))
1046 GNUNET_SERVER_receive_done (client,
1050 msg = (const struct BobComputationMessage *) message;
1051 total_count = ntohl (msg->element_count_total);
1052 contained_count = ntohl (msg->element_count_contained);
1053 if ( (0 == total_count) ||
1054 (0 == contained_count) ||
1055 (UINT16_MAX < contained_count) ||
1056 (msize != (sizeof (struct BobComputationMessage) +
1057 contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) )
1059 GNUNET_break_op (0);
1060 GNUNET_SERVER_receive_done (client,
1064 if (NULL != find_matching_client_session (&msg->session_key))
1067 GNUNET_SERVER_receive_done (client,
1072 s = GNUNET_new (struct BobServiceSession);
1073 s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
1075 s->client_mq = GNUNET_MQ_queue_for_server_client (client);
1076 s->total = total_count;
1077 s->client_received_element_count = contained_count;
1078 s->session_id = msg->session_key;
1079 GNUNET_break (GNUNET_YES ==
1080 GNUNET_CONTAINER_multihashmap_put (client_sessions,
1083 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1084 elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1085 s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total,
1087 s->intersection_set = GNUNET_SET_create (cfg,
1088 GNUNET_SET_OPERATION_INTERSECTION);
1089 for (i = 0; i < contained_count; i++)
1091 if (0 == GNUNET_ntohll (elements[i].value))
1093 elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1096 sizeof (struct GNUNET_SCALARPRODUCT_Element));
1097 if (GNUNET_SYSERR ==
1098 GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1101 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1107 set_elem.data = &elem->key;
1108 set_elem.size = sizeof (elem->key);
1109 set_elem.element_type = 0;
1110 GNUNET_SET_add_element (s->intersection_set,
1113 s->used_element_count++;
1115 GNUNET_SERVER_client_set_user_context (client,
1117 GNUNET_SERVER_receive_done (client,
1119 if (s->total != s->client_received_element_count)
1124 in = find_matching_cadet_session (&s->session_id);
1127 /* nothing yet, wait for Alice */
1130 GNUNET_assert (NULL == in->s);
1134 start_intersection (s);
1139 * Task run during shutdown.
1144 shutdown_task (void *cls)
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");
1185 s = GNUNET_SERVER_client_get_user_context (client,
1186 struct BobServiceSession);
1190 destroy_service_session (s);
1195 * Initialization of the program and message handlers
1197 * @param cls closure
1198 * @param server the initialized server
1199 * @param c configuration to use
1203 struct GNUNET_SERVER_Handle *server,
1204 const struct GNUNET_CONFIGURATION_Handle *c)
1206 static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1207 { &GSS_handle_bob_client_message, NULL,
1208 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB,
1210 { &GSS_handle_bob_client_message_multipart, NULL,
1211 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART_BOB,
1215 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1216 { &handle_alices_computation_request,
1217 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_SESSION_INITIALIZATION,
1218 sizeof (struct EccServiceRequestMessage) },
1219 { &handle_alices_cryptodata_message,
1220 GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_ALICE_CRYPTODATA,
1224 static const uint32_t ports[] = {
1225 GNUNET_APPLICATION_TYPE_SCALARPRODUCT_ECC,
1230 /* We don't really do DLOG, so we can setup with very minimal resources */
1231 edc = GNUNET_CRYPTO_ecc_dlog_prepare (4 /* max value */,
1234 GNUNET_SERVER_add_handlers (server,
1236 GNUNET_SERVER_disconnect_notify (server,
1237 &handle_client_disconnect,
1239 client_sessions = GNUNET_CONTAINER_multihashmap_create (128,
1241 cadet_sessions = GNUNET_CONTAINER_multihashmap_create (128,
1243 my_cadet = GNUNET_CADET_connect (cfg, NULL,
1244 &cb_channel_incoming,
1245 &cb_channel_destruction,
1248 if (NULL == my_cadet)
1250 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1251 _("Connect to CADET failed\n"));
1252 GNUNET_SCHEDULER_shutdown ();
1255 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1261 * The main function for the scalarproduct service.
1263 * @param argc number of arguments from the command line
1264 * @param argv command line arguments
1265 * @return 0 ok, 1 on error
1271 return (GNUNET_OK ==
1272 GNUNET_SERVICE_run (argc, argv,
1273 "scalarproduct-bob",
1274 GNUNET_SERVICE_OPTION_NONE,
1275 &run, NULL)) ? 0 : 1;
1278 /* end of gnunet-service-scalarproduct-ecc_bob.c */