More API function tests...
[oweals/gnunet.git] / src / scalarproduct / gnunet-service-scalarproduct-ecc_bob.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2013-2017 GNUnet e.V.
4
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.
9
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.
14
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.
19  */
20 /**
21  * @file scalarproduct/gnunet-service-scalarproduct-ecc_bob.c
22  * @brief scalarproduct service implementation
23  * @author Christian M. Fuchs
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include <limits.h>
28 #include <gcrypt.h>
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"
38
39 #define LOG(kind,...) GNUNET_log_from (kind, "scalarproduct-bob", __VA_ARGS__)
40
41
42 /**
43  * An encrypted element key-value pair.
44  */
45 struct MpiElement
46 {
47   /**
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.
51    */
52   const struct GNUNET_HashCode *key;
53
54   /**
55    * Value represented (a).
56    */
57   gcry_mpi_t value;
58 };
59
60
61 /**
62  * A scalarproduct session which tracks an offer for a
63  * multiplication service by a local client.
64  */
65 struct BobServiceSession
66 {
67
68   /**
69    * The client this request is related to.
70    */
71   struct GNUNET_SERVICE_Client *client;
72
73   /**
74    * Client message queue.
75    */
76   struct GNUNET_MQ_Handle *client_mq;
77
78   /**
79    * All non-0-value'd elements transmitted to us.
80    */
81   struct GNUNET_CONTAINER_MultiHashMap *intersected_elements;
82
83   /**
84    * Set of elements for which we will be conducting an intersection.
85    * The resulting elements are then used for computing the scalar product.
86    */
87   struct GNUNET_SET_Handle *intersection_set;
88
89   /**
90    * Set of elements for which will conduction an intersection.
91    * the resulting elements are then used for computing the scalar product.
92    */
93   struct GNUNET_SET_OperationHandle *intersection_op;
94
95   /**
96    * Our open port.
97    */
98   struct GNUNET_CADET_Port *port;
99
100   /**
101    * b(Bob)
102    */
103   struct MpiElement *sorted_elements;
104
105   /**
106    * Product of the g_i^{b_i}
107    */
108   gcry_mpi_point_t prod_g_i_b_i;
109
110   /**
111    * Product of the h_i^{b_i}
112    */
113   gcry_mpi_point_t prod_h_i_b_i;
114
115   /**
116    * How many elements will be supplied in total from the client.
117    */
118   uint32_t total;
119
120   /**
121    * Already transferred elements (received) for multipart
122    * messages from client. Always less than @e total.
123    */
124   uint32_t client_received_element_count;
125
126   /**
127    * How many elements actually are used for the scalar product.
128    * Size of the arrays in @e r and @e r_prime.  Also sometimes
129    * used as an index into the arrays during construction.
130    */
131   uint32_t used_element_count;
132
133   /**
134    * Counts the number of values received from Alice by us.
135    * Always less than @e used_element_count.
136    */
137   uint32_t cadet_received_element_count;
138
139   /**
140    * State of this session.   In
141    * #GNUNET_SCALARPRODUCT_STATUS_ACTIVE while operation is
142    * ongoing, afterwards in #GNUNET_SCALARPRODUCT_STATUS_SUCCESS or
143    * #GNUNET_SCALARPRODUCT_STATUS_FAILURE.
144    */
145   enum GNUNET_SCALARPRODUCT_ResponseStatus status;
146
147   /**
148    * Are we already in #destroy_service_session()?
149    */
150   int in_destroy;
151
152   /**
153    * The CADET channel.
154    */
155   struct GNUNET_CADET_Channel *channel;
156
157   /**
158    * Originator's peer identity. (Only for diagnostics.)
159    */
160   struct GNUNET_PeerIdentity peer;
161
162   /**
163    * (hopefully) unique transaction ID
164    */
165   struct GNUNET_HashCode session_id;
166
167   /**
168    * The message queue for this channel.
169    */
170   struct GNUNET_MQ_Handle *cadet_mq;
171
172 };
173
174
175 /**
176  * GNUnet configuration handle
177  */
178 static const struct GNUNET_CONFIGURATION_Handle *cfg;
179
180 /**
181  * Handle to the CADET service.
182  */
183 static struct GNUNET_CADET_Handle *my_cadet;
184
185 /**
186  * Context for DLOG operations on a curve.
187  */
188 static struct GNUNET_CRYPTO_EccDlogContext *edc;
189
190
191 /**
192  * Callback used to free the elements in the map.
193  *
194  * @param cls NULL
195  * @param key key of the element
196  * @param value the value to free
197  */
198 static int
199 free_element_cb (void *cls,
200                  const struct GNUNET_HashCode *key,
201                  void *value)
202 {
203   struct GNUNET_SCALARPRODUCT_Element *element = value;
204
205   GNUNET_free (element);
206   return GNUNET_OK;
207 }
208
209
210 /**
211  * Destroy session state, we are done with it.
212  *
213  * @param session the session to free elements from
214  */
215 static void
216 destroy_service_session (struct BobServiceSession *s)
217 {
218   unsigned int i;
219
220   if (GNUNET_YES == s->in_destroy)
221     return;
222   s->in_destroy = GNUNET_YES;
223   if (NULL != s->client)
224   {
225     struct GNUNET_SERVICE_Client *c = s->client;
226
227     s->client = NULL;
228     GNUNET_SERVICE_client_drop (c);
229   }
230   if (NULL != s->intersected_elements)
231   {
232     GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
233                                            &free_element_cb,
234                                            NULL);
235     GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements);
236     s->intersected_elements = NULL;
237   }
238   if (NULL != s->intersection_op)
239   {
240     GNUNET_SET_operation_cancel (s->intersection_op);
241     s->intersection_op = NULL;
242   }
243   if (NULL != s->intersection_set)
244   {
245     GNUNET_SET_destroy (s->intersection_set);
246     s->intersection_set = NULL;
247   }
248   if (NULL != s->sorted_elements)
249   {
250     for (i=0;i<s->used_element_count;i++)
251       gcry_mpi_release (s->sorted_elements[i].value);
252     GNUNET_free (s->sorted_elements);
253     s->sorted_elements = NULL;
254   }
255   if (NULL != s->prod_g_i_b_i)
256   {
257     gcry_mpi_point_release (s->prod_g_i_b_i);
258     s->prod_g_i_b_i = NULL;
259   }
260   if (NULL != s->prod_h_i_b_i)
261   {
262     gcry_mpi_point_release (s->prod_h_i_b_i);
263     s->prod_h_i_b_i = NULL;
264   }
265   if (NULL != s->port)
266   {
267     GNUNET_CADET_close_port (s->port);
268     s->port = NULL;
269   }
270   if (NULL != s->channel)
271   {
272     GNUNET_CADET_channel_destroy (s->channel);
273     s->channel = NULL;
274   }
275   GNUNET_free (s);
276 }
277
278
279 /**
280  * Notify the client that the session has succeeded or failed.  This
281  * message gets sent to Bob's client if the operation completed or
282  * Alice disconnected.
283  *
284  * @param session the associated client session to fail or succeed
285  */
286 static void
287 prepare_client_end_notification (struct BobServiceSession *session)
288 {
289   struct ClientResponseMessage *msg;
290   struct GNUNET_MQ_Envelope *e;
291
292   if (NULL == session->client_mq)
293     return; /* no client left to be notified */
294   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
295               "Sending session-end notification with status %d to client for session %s\n",
296               session->status,
297               GNUNET_h2s (&session->session_id));
298   e = GNUNET_MQ_msg (msg,
299                      GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
300   msg->range = 0;
301   msg->product_length = htonl (0);
302   msg->status = htonl (session->status);
303   GNUNET_MQ_send (session->client_mq,
304                   e);
305 }
306
307
308 /**
309  * Function called whenever a channel is destroyed.  Should clean up
310  * any associated state.
311  *
312  * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
313  *
314  * @param cls the `struct BobServiceSession`
315  * @param channel connection to the other end (henceforth invalid)
316  * @param channel_ctx place where local state associated
317  *                   with the channel is stored
318  */
319 static void
320 cb_channel_destruction (void *cls,
321                         const struct GNUNET_CADET_Channel *channel)
322 {
323   struct BobServiceSession *s = cls;
324
325   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
326               "Peer disconnected, terminating session %s with peer %s\n",
327               GNUNET_h2s (&s->session_id),
328               GNUNET_i2s (&s->peer));
329   s->channel = NULL;
330   if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
331   {
332     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
333     prepare_client_end_notification (s);
334   }
335   destroy_service_session (s);
336 }
337
338
339 /**
340  * MQ finished giving our last message to CADET, now notify
341  * the client that we are finished.
342  */
343 static void
344 bob_cadet_done_cb (void *cls)
345 {
346   struct BobServiceSession *session = cls;
347
348   session->status = GNUNET_SCALARPRODUCT_STATUS_SUCCESS;
349   prepare_client_end_notification (session);
350 }
351
352
353 /**
354  * Bob generates the response message to be sent to Alice.
355  *
356  * @param s the associated requesting session with Alice
357  */
358 static void
359 transmit_bobs_cryptodata_message (struct BobServiceSession *s)
360 {
361   struct EccBobCryptodataMessage *msg;
362   struct GNUNET_MQ_Envelope *e;
363
364   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
365               "Sending response to Alice\n");
366   e = GNUNET_MQ_msg (msg,
367                      GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_BOB_CRYPTODATA);
368   msg->contained_element_count = htonl (2);
369   if (NULL != s->prod_g_i_b_i)
370     GNUNET_CRYPTO_ecc_point_to_bin (edc,
371                                     s->prod_g_i_b_i,
372                                     &msg->prod_g_i_b_i);
373   if (NULL != s->prod_h_i_b_i)
374     GNUNET_CRYPTO_ecc_point_to_bin (edc,
375                                     s->prod_h_i_b_i,
376                                     &msg->prod_h_i_b_i);
377   GNUNET_MQ_notify_sent (e,
378                          &bob_cadet_done_cb,
379                          s);
380   GNUNET_MQ_send (s->cadet_mq,
381                   e);
382 }
383
384
385 /**
386  * Iterator to copy over messages from the hash map
387  * into an array for sorting.
388  *
389  * @param cls the `struct BobServiceSession *`
390  * @param key the key (unused)
391  * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
392  * TODO: code duplication with Alice!
393  */
394 static int
395 copy_element_cb (void *cls,
396                  const struct GNUNET_HashCode *key,
397                  void *value)
398 {
399   struct BobServiceSession *s = cls;
400   struct GNUNET_SCALARPRODUCT_Element *e = value;
401   gcry_mpi_t mval;
402   int64_t val;
403
404   mval = gcry_mpi_new (0);
405   val = (int64_t) GNUNET_ntohll (e->value);
406   if (0 > val)
407     gcry_mpi_sub_ui (mval, mval, -val);
408   else
409     gcry_mpi_add_ui (mval, mval, val);
410   s->sorted_elements [s->used_element_count].value = mval;
411   s->sorted_elements [s->used_element_count].key = &e->key;
412   s->used_element_count++;
413   return GNUNET_OK;
414 }
415
416
417 /**
418  * Compare two `struct MpiValue`s by key for sorting.
419  *
420  * @param a pointer to first `struct MpiValue *`
421  * @param b pointer to first `struct MpiValue *`
422  * @return -1 for a < b, 0 for a=b, 1 for a > b.
423  * TODO: code duplication with Alice!
424  */
425 static int
426 element_cmp (const void *a,
427              const void *b)
428 {
429   const struct MpiElement *ma = a;
430   const struct MpiElement *mb = b;
431
432   return GNUNET_CRYPTO_hash_cmp (ma->key,
433                                  mb->key);
434 }
435
436
437 /**
438  * Check a multipart-chunk of a request from another service to
439  * calculate a scalarproduct with us.
440  *
441  * @param cls closure (set from #GNUNET_CADET_connect)
442  * @param msg the actual message
443  * @return #GNUNET_OK to keep the connection open,
444  *         #GNUNET_SYSERR to close it (signal serious error)
445  */
446 static int
447 check_alices_cryptodata_message (void *cls,
448                                  const struct EccAliceCryptodataMessage *msg)
449 {
450   struct BobServiceSession *s = cls;
451   uint32_t contained_elements;
452   size_t msg_length;
453   uint16_t msize;
454   unsigned int max;
455
456   msize = ntohs (msg->header.size);
457   if (msize <= sizeof (struct EccAliceCryptodataMessage))
458   {
459     GNUNET_break_op (0);
460     return GNUNET_SYSERR;
461   }
462   contained_elements = ntohl (msg->contained_element_count);
463   /* Our intersection may still be ongoing, but this is nevertheless
464      an upper bound on the required array size */
465   max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements);
466   msg_length = sizeof (struct EccAliceCryptodataMessage)
467     + contained_elements * sizeof (struct GNUNET_CRYPTO_EccPoint) * 2;
468   if ( (msize != msg_length) ||
469        (0 == contained_elements) ||
470        (contained_elements > UINT16_MAX) ||
471        (max < contained_elements + s->cadet_received_element_count) )
472   {
473     GNUNET_break_op (0);
474     return GNUNET_SYSERR;
475   }
476   return GNUNET_OK;
477 }
478
479
480 /**
481  * Handle a multipart-chunk of a request from another service to
482  * calculate a scalarproduct with us.
483  *
484  * @param cls closure (set from #GNUNET_CADET_connect)
485  * @param msg the actual message
486  */
487 static void
488 handle_alices_cryptodata_message (void *cls,
489                                   const struct EccAliceCryptodataMessage *msg)
490 {
491   struct BobServiceSession *s = cls;
492   const struct GNUNET_CRYPTO_EccPoint *payload;
493   uint32_t contained_elements;
494   unsigned int max;
495   unsigned int i;
496   const struct MpiElement *b_i;
497   gcry_mpi_point_t tmp;
498   gcry_mpi_point_t g_i;
499   gcry_mpi_point_t h_i;
500   gcry_mpi_point_t g_i_b_i;
501   gcry_mpi_point_t h_i_b_i;
502
503   contained_elements = ntohl (msg->contained_element_count);
504   max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements);
505   /* sort our vector for the computation */
506   if (NULL == s->sorted_elements)
507   {
508     s->sorted_elements
509       = GNUNET_new_array (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements),
510                           struct MpiElement);
511     s->used_element_count = 0;
512     GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
513                                            &copy_element_cb,
514                                            s);
515     qsort (s->sorted_elements,
516            s->used_element_count,
517            sizeof (struct MpiElement),
518            &element_cmp);
519   }
520
521   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
522               "Received %u crypto values from Alice\n",
523               (unsigned int) contained_elements);
524   payload = (const struct GNUNET_CRYPTO_EccPoint *) &msg[1];
525
526   for (i=0;i<contained_elements;i++)
527   {
528     b_i = &s->sorted_elements[i + s->cadet_received_element_count];
529     g_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
530                                           &payload[i * 2]);
531     g_i_b_i = GNUNET_CRYPTO_ecc_pmul_mpi (edc,
532                                           g_i,
533                                           b_i->value);
534     gcry_mpi_point_release (g_i);
535     h_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
536                                           &payload[i * 2 + 1]);
537     h_i_b_i = GNUNET_CRYPTO_ecc_pmul_mpi (edc,
538                                           h_i,
539                                           b_i->value);
540     gcry_mpi_point_release (h_i);
541     if (0 == i + s->cadet_received_element_count)
542     {
543       /* first iteration, nothing to add */
544       s->prod_g_i_b_i = g_i_b_i;
545       s->prod_h_i_b_i = h_i_b_i;
546     }
547     else
548     {
549       /* further iterations, cummulate resulting value */
550       tmp = GNUNET_CRYPTO_ecc_add (edc,
551                                    s->prod_g_i_b_i,
552                                    g_i_b_i);
553       gcry_mpi_point_release (s->prod_g_i_b_i);
554       gcry_mpi_point_release (g_i_b_i);
555       s->prod_g_i_b_i = tmp;
556       tmp = GNUNET_CRYPTO_ecc_add (edc,
557                                    s->prod_h_i_b_i,
558                                    h_i_b_i);
559       gcry_mpi_point_release (s->prod_h_i_b_i);
560       gcry_mpi_point_release (h_i_b_i);
561       s->prod_h_i_b_i = tmp;
562     }
563   }
564   s->cadet_received_element_count += contained_elements;
565   if ( (s->cadet_received_element_count == max) &&
566        (NULL == s->intersection_op) )
567   {
568     /* intersection has finished also on our side, and
569        we got the full set, so we can proceed with the
570        CADET response(s) */
571     transmit_bobs_cryptodata_message (s);
572   }
573   GNUNET_CADET_receive_done (s->channel);
574 }
575
576
577 /**
578  * Callback for set operation results. Called for each element
579  * that needs to be removed from the result set.
580  *
581  * @param cls closure with the `struct BobServiceSession`
582  * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
583  * @param status what has happened with the set intersection?
584  */
585 static void
586 cb_intersection_element_removed (void *cls,
587                                  const struct GNUNET_SET_Element *element,
588                                  enum GNUNET_SET_Status status)
589 {
590   struct BobServiceSession *s = cls;
591   struct GNUNET_SCALARPRODUCT_Element *se;
592
593   switch (status)
594   {
595   case GNUNET_SET_STATUS_OK:
596     /* this element has been removed from the set */
597     se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
598                                             element->data);
599     GNUNET_assert (NULL != se);
600     LOG (GNUNET_ERROR_TYPE_DEBUG,
601          "Removed element with key %s and value %lld\n",
602          GNUNET_h2s (&se->key),
603          (long long) GNUNET_ntohll (se->value));
604     GNUNET_assert (GNUNET_YES ==
605                    GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
606                                                          element->data,
607                                                          se));
608     GNUNET_free (se);
609     return;
610   case GNUNET_SET_STATUS_DONE:
611     s->intersection_op = NULL;
612     GNUNET_break (NULL == s->intersection_set);
613     GNUNET_CADET_receive_done (s->channel);
614     LOG (GNUNET_ERROR_TYPE_DEBUG,
615          "Finished intersection, %d items remain\n",
616          GNUNET_CONTAINER_multihashmap_size (s->intersected_elements));
617     if (s->client_received_element_count ==
618         GNUNET_CONTAINER_multihashmap_size (s->intersected_elements))
619     {
620       /* CADET transmission from Alice is also already done,
621          start with our own reply */
622       transmit_bobs_cryptodata_message (s);
623     }
624     return;
625   case GNUNET_SET_STATUS_HALF_DONE:
626     /* unexpected for intersection */
627     GNUNET_break (0);
628     return;
629   case GNUNET_SET_STATUS_FAILURE:
630     /* unhandled status code */
631     LOG (GNUNET_ERROR_TYPE_DEBUG,
632          "Set intersection failed!\n");
633     s->intersection_op = NULL;
634     if (NULL != s->intersection_set)
635     {
636       GNUNET_SET_destroy (s->intersection_set);
637       s->intersection_set = NULL;
638     }
639     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
640     prepare_client_end_notification (s);
641     return;
642   default:
643     GNUNET_break (0);
644     return;
645   }
646 }
647
648
649 /**
650  * We've paired up a client session with an incoming CADET request.
651  * Initiate set intersection work.
652  *
653  * @param s client session to start intersection for
654  */
655 static void
656 start_intersection (struct BobServiceSession *s)
657 {
658   struct GNUNET_HashCode set_sid;
659
660   GNUNET_CRYPTO_hash (&s->session_id,
661                       sizeof (struct GNUNET_HashCode),
662                       &set_sid);
663   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
664               "Got session with key %s and %u elements, starting intersection.\n",
665               GNUNET_h2s (&s->session_id),
666               (unsigned int) s->total);
667
668   s->intersection_op
669     = GNUNET_SET_prepare (&s->peer,
670                           &set_sid,
671                           NULL,
672                           GNUNET_SET_RESULT_REMOVED,
673                           &cb_intersection_element_removed,
674                           s);
675   if (GNUNET_OK !=
676       GNUNET_SET_commit (s->intersection_op,
677                          s->intersection_set))
678   {
679     GNUNET_break (0);
680     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
681     prepare_client_end_notification (s);
682     return;
683   }
684   GNUNET_SET_destroy (s->intersection_set);
685   s->intersection_set = NULL;
686 }
687
688
689 /**
690  * Handle a request from Alice to calculate a scalarproduct with us (Bob).
691  *
692  * @param cls closure (set from #GNUNET_CADET_connect)
693  * @param msg the actual message
694  */
695 static void
696 handle_alices_computation_request (void *cls,
697                                    const struct EccServiceRequestMessage *msg)
698 {
699   struct BobServiceSession *s = cls;
700
701   s->session_id = msg->session_id; // ??
702   if (s->client_received_element_count < s->total)
703   {
704     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
705                 "Alice ready, still waiting for Bob client data!\n");
706     return;
707   }
708   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
709               "Both ready, launching intersection!\n");
710   start_intersection (s);
711 }
712
713
714 /**
715  * Function called for inbound channels on Bob's end.  Does some
716  * preliminary initialization, more happens after we get Alice's first
717  * message.
718  *
719  * @param cls our `struct BobServiceSession`
720  * @param channel new handle to the channel
721  * @param initiator peer that started the channel
722  * @return session associated with the channel
723  */
724 static void *
725 cb_channel_incoming (void *cls,
726                      struct GNUNET_CADET_Channel *channel,
727                      const struct GNUNET_PeerIdentity *initiator)
728 {
729   struct BobServiceSession *s = cls;
730
731   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
732               "New incoming channel from peer %s.\n",
733               GNUNET_i2s (initiator));
734   GNUNET_CADET_close_port (s->port);
735   s->port = NULL;
736   s->peer = *initiator;
737   s->channel = channel;
738   s->cadet_mq = GNUNET_CADET_get_mq (s->channel);
739   return s;
740 }
741
742
743 /**
744  * We're receiving additional set data. Check it is well-formed.
745  *
746  * @param cls identification of the client
747  * @param msg the actual message
748  * @return #GNUNET_OK if @a msg is well-formed
749  */
750 static int
751 check_bob_client_message_multipart (void *cls,
752                                     const struct ComputationBobCryptodataMultipartMessage *msg)
753 {
754   struct BobServiceSession *s = cls;
755   uint32_t contained_count;
756   uint16_t msize;
757
758   msize = ntohs (msg->header.size);
759   contained_count = ntohl (msg->element_count_contained);
760   if ( (msize != (sizeof (struct ComputationBobCryptodataMultipartMessage) +
761                   contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ||
762        (0 == contained_count) ||
763        (UINT16_MAX < contained_count) ||
764        (s->total == s->client_received_element_count) ||
765        (s->total < s->client_received_element_count + contained_count) )
766   {
767     GNUNET_break (0);
768     return GNUNET_SYSERR;
769   }
770   return GNUNET_OK;
771 }
772
773
774 /**
775  * We're receiving additional set data. Add it to our
776  * set and if we are done, initiate the transaction.
777  *
778  * @param cls identification of the client
779  * @param msg the actual message
780  */
781 static void
782 handle_bob_client_message_multipart (void *cls,
783                                      const struct ComputationBobCryptodataMultipartMessage *msg)
784 {
785   struct BobServiceSession *s = cls;
786   uint32_t contained_count;
787   const struct GNUNET_SCALARPRODUCT_Element *elements;
788   struct GNUNET_SET_Element set_elem;
789   struct GNUNET_SCALARPRODUCT_Element *elem;
790
791   contained_count = ntohl (msg->element_count_contained);
792   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
793   for (uint32_t i = 0; i < contained_count; i++)
794   {
795     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
796     GNUNET_memcpy (elem,
797                    &elements[i],
798                    sizeof (struct GNUNET_SCALARPRODUCT_Element));
799     if (GNUNET_SYSERR ==
800         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
801                                            &elem->key,
802                                            elem,
803                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
804     {
805       GNUNET_break (0);
806       GNUNET_free (elem);
807       continue;
808     }
809     set_elem.data = &elem->key;
810     set_elem.size = sizeof (elem->key);
811     set_elem.element_type = 0;
812     GNUNET_SET_add_element (s->intersection_set,
813                             &set_elem,
814                             NULL, NULL);
815   }
816   s->client_received_element_count += contained_count;
817   GNUNET_SERVICE_client_continue (s->client);
818   if (s->total != s->client_received_element_count)
819   {
820     /* more to come */
821     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
822                 "Request still partial, waiting for more client data!\n");
823     return;
824   }
825   if (NULL == s->channel)
826   {
827     /* no Alice waiting for this request, wait for Alice */
828     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
829                 "Client ready, still waiting for Alice!\n");
830     return;
831   }
832   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
833               "Both ready, launching intersection!\n");
834   start_intersection (s);
835 }
836
837
838 /**
839  * Handler for Bob's a client request message.  Check @a msg is
840  * well-formed.
841  *
842  * @param cls identification of the client
843  * @param msg the actual message
844  * @return #GNUNET_OK if @a msg is well-formed
845  */
846 static int
847 check_bob_client_message (void *cls,
848                           const struct BobComputationMessage *msg)
849 {
850   struct BobServiceSession *s = cls;
851   uint32_t contained_count;
852   uint32_t total_count;
853   uint16_t msize;
854
855   if (GNUNET_SCALARPRODUCT_STATUS_INIT != s->status)
856   {
857     GNUNET_break (0);
858     return GNUNET_SYSERR;
859   }
860   msize = ntohs (msg->header.size);
861   total_count = ntohl (msg->element_count_total);
862   contained_count = ntohl (msg->element_count_contained);
863   if ( (0 == total_count) ||
864        (0 == contained_count) ||
865        (UINT16_MAX < contained_count) ||
866        (msize != (sizeof (struct BobComputationMessage) +
867                   contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) )
868   {
869     GNUNET_break_op (0);
870     return GNUNET_SYSERR;
871   }
872   return GNUNET_OK;
873 }
874
875
876 /**
877  * Handler for Bob's a client request message.  Bob is in the response
878  * role, keep the values + session and waiting for a matching session
879  * or process a waiting request from Alice.
880  *
881  * @param cls identification of the client
882  * @param msg the actual message
883  */
884 static void
885 handle_bob_client_message (void *cls,
886                            const struct BobComputationMessage *msg)
887 {
888   struct BobServiceSession *s = cls;
889   struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
890     GNUNET_MQ_hd_fixed_size (alices_computation_request,
891                              GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_SESSION_INITIALIZATION,
892                              struct EccServiceRequestMessage,
893                              s),
894     GNUNET_MQ_hd_var_size (alices_cryptodata_message,
895                            GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_ALICE_CRYPTODATA,
896                            struct EccAliceCryptodataMessage,
897                            s),
898     GNUNET_MQ_handler_end ()
899   };
900   uint32_t contained_count;
901   uint32_t total_count;
902   const struct GNUNET_SCALARPRODUCT_Element *elements;
903   struct GNUNET_SET_Element set_elem;
904   struct GNUNET_SCALARPRODUCT_Element *elem;
905
906   total_count = ntohl (msg->element_count_total);
907   contained_count = ntohl (msg->element_count_contained);
908
909   s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
910   s->total = total_count;
911   s->client_received_element_count = contained_count;
912   s->session_id = msg->session_key;
913   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
914   s->intersected_elements
915     = GNUNET_CONTAINER_multihashmap_create (s->total,
916                                             GNUNET_YES);
917   s->intersection_set
918     = GNUNET_SET_create (cfg,
919                          GNUNET_SET_OPERATION_INTERSECTION);
920   for (uint32_t i = 0; i < contained_count; i++)
921   {
922     if (0 == GNUNET_ntohll (elements[i].value))
923       continue;
924     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
925     GNUNET_memcpy (elem,
926             &elements[i],
927             sizeof (struct GNUNET_SCALARPRODUCT_Element));
928     if (GNUNET_SYSERR ==
929         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
930                                            &elem->key,
931                                            elem,
932                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
933     {
934       GNUNET_break (0);
935       GNUNET_free (elem);
936       continue;
937     }
938     set_elem.data = &elem->key;
939     set_elem.size = sizeof (elem->key);
940     set_elem.element_type = 0;
941     GNUNET_SET_add_element (s->intersection_set,
942                             &set_elem,
943                             NULL, NULL);
944     s->used_element_count++;
945   }
946   GNUNET_SERVICE_client_continue (s->client);
947   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
948               "Received client request, opening port %s!\n",
949               GNUNET_h2s (&msg->session_key));
950   s->port = GNUNET_CADET_open_porT (my_cadet,
951                                     &msg->session_key,
952                                     &cb_channel_incoming,
953                                     s,
954                                     NULL,
955                                     &cb_channel_destruction,
956                                     cadet_handlers);
957   if (NULL == s->port)
958   {
959     GNUNET_break (0);
960     GNUNET_SERVICE_client_drop (s->client);
961     return;
962   }
963 }
964
965
966 /**
967  * Task run during shutdown.
968  *
969  * @param cls unused
970  */
971 static void
972 shutdown_task (void *cls)
973 {
974   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
975               "Shutting down, initiating cleanup.\n");
976   // FIXME: we have to cut our connections to CADET first!
977   if (NULL != my_cadet)
978   {
979     GNUNET_CADET_disconnect (my_cadet);
980     my_cadet = NULL;
981   }
982   if (NULL != edc)
983   {
984     GNUNET_CRYPTO_ecc_dlog_release (edc);
985     edc = NULL;
986   }
987 }
988
989
990 /**
991  * A client connected.
992  *
993  * Setup the associated data structure.
994  *
995  * @param cls closure, NULL
996  * @param client identification of the client
997  * @param mq message queue to communicate with @a client
998  * @return our `struct BobServiceSession`
999  */
1000 static void *
1001 client_connect_cb (void *cls,
1002                    struct GNUNET_SERVICE_Client *client,
1003                    struct GNUNET_MQ_Handle *mq)
1004 {
1005   struct BobServiceSession *s;
1006
1007   s = GNUNET_new (struct BobServiceSession);
1008   s->client = client;
1009   s->client_mq = mq;
1010   return s;
1011 }
1012
1013
1014 /**
1015  * A client disconnected.
1016  *
1017  * Remove the associated session(s), release data structures
1018  * and cancel pending outgoing transmissions to the client.
1019  *
1020  * @param cls closure, NULL
1021  * @param client identification of the client
1022  * @param app_cls our `struct BobServiceSession`
1023  */
1024 static void
1025 client_disconnect_cb (void *cls,
1026                       struct GNUNET_SERVICE_Client *client,
1027                       void *app_cls)
1028 {
1029   struct BobServiceSession *s = app_cls;
1030
1031   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1032               "Client disconnected from us.\n");
1033   s->client = NULL;
1034   destroy_service_session (s);
1035 }
1036
1037
1038 /**
1039  * Initialization of the program and message handlers
1040  *
1041  * @param cls closure
1042  * @param c configuration to use
1043  * @param service the initialized service
1044  */
1045 static void
1046 run (void *cls,
1047      const struct GNUNET_CONFIGURATION_Handle *c,
1048      struct GNUNET_SERVICE_Handle *service)
1049 {
1050   cfg = c;
1051   /* We don't really do DLOG, so we can setup with very minimal resources */
1052   edc = GNUNET_CRYPTO_ecc_dlog_prepare (4 /* max value */,
1053                                         2 /* RAM */);
1054   my_cadet = GNUNET_CADET_connecT (cfg);
1055   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1056                                  NULL);
1057   if (NULL == my_cadet)
1058   {
1059     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1060                 _("Connect to CADET failed\n"));
1061     GNUNET_SCHEDULER_shutdown ();
1062     return;
1063   }
1064 }
1065
1066
1067 /**
1068  * Define "main" method using service macro.
1069  */
1070 GNUNET_SERVICE_MAIN
1071 ("scalarproduct-bob",
1072  GNUNET_SERVICE_OPTION_NONE,
1073  &run,
1074  &client_connect_cb,
1075  &client_disconnect_cb,
1076  NULL,
1077  GNUNET_MQ_hd_var_size (bob_client_message,
1078                         GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB,
1079                         struct BobComputationMessage,
1080                         NULL),
1081  GNUNET_MQ_hd_var_size (bob_client_message_multipart,
1082                         GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_BOB,
1083                         struct ComputationBobCryptodataMultipartMessage,
1084                         NULL),
1085  GNUNET_MQ_handler_end ());
1086
1087
1088 /* end of gnunet-service-scalarproduct-ecc_bob.c */