Merge branch 'master' of ssh://gnunet.org/gnunet
[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 current_size current set size
584  * @param status what has happened with the set intersection?
585  */
586 static void
587 cb_intersection_element_removed (void *cls,
588                                  const struct GNUNET_SET_Element *element,
589                                  uint64_t current_size,
590                                  enum GNUNET_SET_Status status)
591 {
592   struct BobServiceSession *s = cls;
593   struct GNUNET_SCALARPRODUCT_Element *se;
594
595   switch (status)
596   {
597   case GNUNET_SET_STATUS_OK:
598     /* this element has been removed from the set */
599     se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
600                                             element->data);
601     GNUNET_assert (NULL != se);
602     LOG (GNUNET_ERROR_TYPE_DEBUG,
603          "Removed element with key %s and value %lld\n",
604          GNUNET_h2s (&se->key),
605          (long long) GNUNET_ntohll (se->value));
606     GNUNET_assert (GNUNET_YES ==
607                    GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
608                                                          element->data,
609                                                          se));
610     GNUNET_free (se);
611     return;
612   case GNUNET_SET_STATUS_DONE:
613     s->intersection_op = NULL;
614     GNUNET_break (NULL == s->intersection_set);
615     GNUNET_CADET_receive_done (s->channel);
616     LOG (GNUNET_ERROR_TYPE_DEBUG,
617          "Finished intersection, %d items remain\n",
618          GNUNET_CONTAINER_multihashmap_size (s->intersected_elements));
619     if (s->client_received_element_count ==
620         GNUNET_CONTAINER_multihashmap_size (s->intersected_elements))
621     {
622       /* CADET transmission from Alice is also already done,
623          start with our own reply */
624       transmit_bobs_cryptodata_message (s);
625     }
626     return;
627   case GNUNET_SET_STATUS_HALF_DONE:
628     /* unexpected for intersection */
629     GNUNET_break (0);
630     return;
631   case GNUNET_SET_STATUS_FAILURE:
632     /* unhandled status code */
633     LOG (GNUNET_ERROR_TYPE_DEBUG,
634          "Set intersection failed!\n");
635     s->intersection_op = NULL;
636     if (NULL != s->intersection_set)
637     {
638       GNUNET_SET_destroy (s->intersection_set);
639       s->intersection_set = NULL;
640     }
641     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
642     prepare_client_end_notification (s);
643     return;
644   default:
645     GNUNET_break (0);
646     return;
647   }
648 }
649
650
651 /**
652  * We've paired up a client session with an incoming CADET request.
653  * Initiate set intersection work.
654  *
655  * @param s client session to start intersection for
656  */
657 static void
658 start_intersection (struct BobServiceSession *s)
659 {
660   struct GNUNET_HashCode set_sid;
661
662   GNUNET_CRYPTO_hash (&s->session_id,
663                       sizeof (struct GNUNET_HashCode),
664                       &set_sid);
665   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
666               "Got session with key %s and %u elements, starting intersection.\n",
667               GNUNET_h2s (&s->session_id),
668               (unsigned int) s->total);
669
670   s->intersection_op
671     = GNUNET_SET_prepare (&s->peer,
672                           &set_sid,
673                           NULL,
674                           GNUNET_SET_RESULT_REMOVED,
675                           (struct GNUNET_SET_Option[]) {{ 0 }},
676                           &cb_intersection_element_removed,
677                           s);
678   if (GNUNET_OK !=
679       GNUNET_SET_commit (s->intersection_op,
680                          s->intersection_set))
681   {
682     GNUNET_break (0);
683     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
684     prepare_client_end_notification (s);
685     return;
686   }
687   GNUNET_SET_destroy (s->intersection_set);
688   s->intersection_set = NULL;
689 }
690
691
692 /**
693  * Handle a request from Alice to calculate a scalarproduct with us (Bob).
694  *
695  * @param cls closure (set from #GNUNET_CADET_connect)
696  * @param msg the actual message
697  */
698 static void
699 handle_alices_computation_request (void *cls,
700                                    const struct EccServiceRequestMessage *msg)
701 {
702   struct BobServiceSession *s = cls;
703
704   s->session_id = msg->session_id; // ??
705   if (s->client_received_element_count < s->total)
706   {
707     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
708                 "Alice ready, still waiting for Bob client data!\n");
709     return;
710   }
711   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
712               "Both ready, launching intersection!\n");
713   start_intersection (s);
714 }
715
716
717 /**
718  * Function called for inbound channels on Bob's end.  Does some
719  * preliminary initialization, more happens after we get Alice's first
720  * message.
721  *
722  * @param cls our `struct BobServiceSession`
723  * @param channel new handle to the channel
724  * @param initiator peer that started the channel
725  * @return session associated with the channel
726  */
727 static void *
728 cb_channel_incoming (void *cls,
729                      struct GNUNET_CADET_Channel *channel,
730                      const struct GNUNET_PeerIdentity *initiator)
731 {
732   struct BobServiceSession *s = cls;
733
734   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
735               "New incoming channel from peer %s.\n",
736               GNUNET_i2s (initiator));
737   GNUNET_CADET_close_port (s->port);
738   s->port = NULL;
739   s->peer = *initiator;
740   s->channel = channel;
741   s->cadet_mq = GNUNET_CADET_get_mq (s->channel);
742   return s;
743 }
744
745
746 /**
747  * We're receiving additional set data. Check it is well-formed.
748  *
749  * @param cls identification of the client
750  * @param msg the actual message
751  * @return #GNUNET_OK if @a msg is well-formed
752  */
753 static int
754 check_bob_client_message_multipart (void *cls,
755                                     const struct ComputationBobCryptodataMultipartMessage *msg)
756 {
757   struct BobServiceSession *s = cls;
758   uint32_t contained_count;
759   uint16_t msize;
760
761   msize = ntohs (msg->header.size);
762   contained_count = ntohl (msg->element_count_contained);
763   if ( (msize != (sizeof (struct ComputationBobCryptodataMultipartMessage) +
764                   contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ||
765        (0 == contained_count) ||
766        (UINT16_MAX < contained_count) ||
767        (s->total == s->client_received_element_count) ||
768        (s->total < s->client_received_element_count + contained_count) )
769   {
770     GNUNET_break (0);
771     return GNUNET_SYSERR;
772   }
773   return GNUNET_OK;
774 }
775
776
777 /**
778  * We're receiving additional set data. Add it to our
779  * set and if we are done, initiate the transaction.
780  *
781  * @param cls identification of the client
782  * @param msg the actual message
783  */
784 static void
785 handle_bob_client_message_multipart (void *cls,
786                                      const struct ComputationBobCryptodataMultipartMessage *msg)
787 {
788   struct BobServiceSession *s = cls;
789   uint32_t contained_count;
790   const struct GNUNET_SCALARPRODUCT_Element *elements;
791   struct GNUNET_SET_Element set_elem;
792   struct GNUNET_SCALARPRODUCT_Element *elem;
793
794   contained_count = ntohl (msg->element_count_contained);
795   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
796   for (uint32_t i = 0; i < contained_count; i++)
797   {
798     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
799     GNUNET_memcpy (elem,
800                    &elements[i],
801                    sizeof (struct GNUNET_SCALARPRODUCT_Element));
802     if (GNUNET_SYSERR ==
803         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
804                                            &elem->key,
805                                            elem,
806                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
807     {
808       GNUNET_break (0);
809       GNUNET_free (elem);
810       continue;
811     }
812     set_elem.data = &elem->key;
813     set_elem.size = sizeof (elem->key);
814     set_elem.element_type = 0;
815     GNUNET_SET_add_element (s->intersection_set,
816                             &set_elem,
817                             NULL, NULL);
818   }
819   s->client_received_element_count += contained_count;
820   GNUNET_SERVICE_client_continue (s->client);
821   if (s->total != s->client_received_element_count)
822   {
823     /* more to come */
824     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
825                 "Request still partial, waiting for more client data!\n");
826     return;
827   }
828   if (NULL == s->channel)
829   {
830     /* no Alice waiting for this request, wait for Alice */
831     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
832                 "Client ready, still waiting for Alice!\n");
833     return;
834   }
835   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
836               "Both ready, launching intersection!\n");
837   start_intersection (s);
838 }
839
840
841 /**
842  * Handler for Bob's a client request message.  Check @a msg is
843  * well-formed.
844  *
845  * @param cls identification of the client
846  * @param msg the actual message
847  * @return #GNUNET_OK if @a msg is well-formed
848  */
849 static int
850 check_bob_client_message (void *cls,
851                           const struct BobComputationMessage *msg)
852 {
853   struct BobServiceSession *s = cls;
854   uint32_t contained_count;
855   uint32_t total_count;
856   uint16_t msize;
857
858   if (GNUNET_SCALARPRODUCT_STATUS_INIT != s->status)
859   {
860     GNUNET_break (0);
861     return GNUNET_SYSERR;
862   }
863   msize = ntohs (msg->header.size);
864   total_count = ntohl (msg->element_count_total);
865   contained_count = ntohl (msg->element_count_contained);
866   if ( (0 == total_count) ||
867        (0 == contained_count) ||
868        (UINT16_MAX < contained_count) ||
869        (msize != (sizeof (struct BobComputationMessage) +
870                   contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) )
871   {
872     GNUNET_break_op (0);
873     return GNUNET_SYSERR;
874   }
875   return GNUNET_OK;
876 }
877
878
879 /**
880  * Handler for Bob's a client request message.  Bob is in the response
881  * role, keep the values + session and waiting for a matching session
882  * or process a waiting request from Alice.
883  *
884  * @param cls identification of the client
885  * @param msg the actual message
886  */
887 static void
888 handle_bob_client_message (void *cls,
889                            const struct BobComputationMessage *msg)
890 {
891   struct BobServiceSession *s = cls;
892   struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
893     GNUNET_MQ_hd_fixed_size (alices_computation_request,
894                              GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_SESSION_INITIALIZATION,
895                              struct EccServiceRequestMessage,
896                              s),
897     GNUNET_MQ_hd_var_size (alices_cryptodata_message,
898                            GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_ALICE_CRYPTODATA,
899                            struct EccAliceCryptodataMessage,
900                            s),
901     GNUNET_MQ_handler_end ()
902   };
903   uint32_t contained_count;
904   uint32_t total_count;
905   const struct GNUNET_SCALARPRODUCT_Element *elements;
906   struct GNUNET_SET_Element set_elem;
907   struct GNUNET_SCALARPRODUCT_Element *elem;
908
909   total_count = ntohl (msg->element_count_total);
910   contained_count = ntohl (msg->element_count_contained);
911
912   s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
913   s->total = total_count;
914   s->client_received_element_count = contained_count;
915   s->session_id = msg->session_key;
916   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
917   s->intersected_elements
918     = GNUNET_CONTAINER_multihashmap_create (s->total,
919                                             GNUNET_YES);
920   s->intersection_set
921     = GNUNET_SET_create (cfg,
922                          GNUNET_SET_OPERATION_INTERSECTION);
923   for (uint32_t i = 0; i < contained_count; i++)
924   {
925     if (0 == GNUNET_ntohll (elements[i].value))
926       continue;
927     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
928     GNUNET_memcpy (elem,
929             &elements[i],
930             sizeof (struct GNUNET_SCALARPRODUCT_Element));
931     if (GNUNET_SYSERR ==
932         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
933                                            &elem->key,
934                                            elem,
935                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
936     {
937       GNUNET_break (0);
938       GNUNET_free (elem);
939       continue;
940     }
941     set_elem.data = &elem->key;
942     set_elem.size = sizeof (elem->key);
943     set_elem.element_type = 0;
944     GNUNET_SET_add_element (s->intersection_set,
945                             &set_elem,
946                             NULL, NULL);
947     s->used_element_count++;
948   }
949   GNUNET_SERVICE_client_continue (s->client);
950   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
951               "Received client request, opening port %s!\n",
952               GNUNET_h2s (&msg->session_key));
953   s->port = GNUNET_CADET_open_porT (my_cadet,
954                                     &msg->session_key,
955                                     &cb_channel_incoming,
956                                     s,
957                                     NULL,
958                                     &cb_channel_destruction,
959                                     cadet_handlers);
960   if (NULL == s->port)
961   {
962     GNUNET_break (0);
963     GNUNET_SERVICE_client_drop (s->client);
964     return;
965   }
966 }
967
968
969 /**
970  * Task run during shutdown.
971  *
972  * @param cls unused
973  */
974 static void
975 shutdown_task (void *cls)
976 {
977   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
978               "Shutting down, initiating cleanup.\n");
979   // FIXME: we have to cut our connections to CADET first!
980   if (NULL != my_cadet)
981   {
982     GNUNET_CADET_disconnect (my_cadet);
983     my_cadet = NULL;
984   }
985   if (NULL != edc)
986   {
987     GNUNET_CRYPTO_ecc_dlog_release (edc);
988     edc = NULL;
989   }
990 }
991
992
993 /**
994  * A client connected.
995  *
996  * Setup the associated data structure.
997  *
998  * @param cls closure, NULL
999  * @param client identification of the client
1000  * @param mq message queue to communicate with @a client
1001  * @return our `struct BobServiceSession`
1002  */
1003 static void *
1004 client_connect_cb (void *cls,
1005                    struct GNUNET_SERVICE_Client *client,
1006                    struct GNUNET_MQ_Handle *mq)
1007 {
1008   struct BobServiceSession *s;
1009
1010   s = GNUNET_new (struct BobServiceSession);
1011   s->client = client;
1012   s->client_mq = mq;
1013   return s;
1014 }
1015
1016
1017 /**
1018  * A client disconnected.
1019  *
1020  * Remove the associated session(s), release data structures
1021  * and cancel pending outgoing transmissions to the client.
1022  *
1023  * @param cls closure, NULL
1024  * @param client identification of the client
1025  * @param app_cls our `struct BobServiceSession`
1026  */
1027 static void
1028 client_disconnect_cb (void *cls,
1029                       struct GNUNET_SERVICE_Client *client,
1030                       void *app_cls)
1031 {
1032   struct BobServiceSession *s = app_cls;
1033
1034   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1035               "Client disconnected from us.\n");
1036   s->client = NULL;
1037   destroy_service_session (s);
1038 }
1039
1040
1041 /**
1042  * Initialization of the program and message handlers
1043  *
1044  * @param cls closure
1045  * @param c configuration to use
1046  * @param service the initialized service
1047  */
1048 static void
1049 run (void *cls,
1050      const struct GNUNET_CONFIGURATION_Handle *c,
1051      struct GNUNET_SERVICE_Handle *service)
1052 {
1053   cfg = c;
1054   /* We don't really do DLOG, so we can setup with very minimal resources */
1055   edc = GNUNET_CRYPTO_ecc_dlog_prepare (4 /* max value */,
1056                                         2 /* RAM */);
1057   my_cadet = GNUNET_CADET_connecT (cfg);
1058   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1059                                  NULL);
1060   if (NULL == my_cadet)
1061   {
1062     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1063                 _("Connect to CADET failed\n"));
1064     GNUNET_SCHEDULER_shutdown ();
1065     return;
1066   }
1067 }
1068
1069
1070 /**
1071  * Define "main" method using service macro.
1072  */
1073 GNUNET_SERVICE_MAIN
1074 ("scalarproduct-bob",
1075  GNUNET_SERVICE_OPTION_NONE,
1076  &run,
1077  &client_connect_cb,
1078  &client_disconnect_cb,
1079  NULL,
1080  GNUNET_MQ_hd_var_size (bob_client_message,
1081                         GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB,
1082                         struct BobComputationMessage,
1083                         NULL),
1084  GNUNET_MQ_hd_var_size (bob_client_message_multipart,
1085                         GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MULTIPART_BOB,
1086                         struct ComputationBobCryptodataMultipartMessage,
1087                         NULL),
1088  GNUNET_MQ_handler_end ());
1089
1090
1091 /* end of gnunet-service-scalarproduct-ecc_bob.c */