-fix (C) notices
[oweals/gnunet.git] / src / scalarproduct / gnunet-service-scalarproduct-ecc_bob.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2013-2015 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  * An incoming session from CADET.
63  */
64 struct CadetIncomingSession;
65
66
67 /**
68  * A scalarproduct session which tracks an offer for a
69  * multiplication service by a local client.
70  */
71 struct BobServiceSession
72 {
73
74   /**
75    * (hopefully) unique transaction ID
76    */
77   struct GNUNET_HashCode session_id;
78
79   /**
80    * The client this request is related to.
81    */
82   struct GNUNET_SERVER_Client *client;
83
84   /**
85    * Client message queue.
86    */
87   struct GNUNET_MQ_Handle *client_mq;
88
89   /**
90    * All non-0-value'd elements transmitted to us.
91    */
92   struct GNUNET_CONTAINER_MultiHashMap *intersected_elements;
93
94   /**
95    * Set of elements for which we will be conducting an intersection.
96    * The resulting elements are then used for computing the scalar product.
97    */
98   struct GNUNET_SET_Handle *intersection_set;
99
100   /**
101    * Set of elements for which will conduction an intersection.
102    * the resulting elements are then used for computing the scalar product.
103    */
104   struct GNUNET_SET_OperationHandle *intersection_op;
105
106   /**
107    * b(Bob)
108    */
109   struct MpiElement *sorted_elements;
110
111   /**
112    * Product of the g_i^{b_i}
113    */
114   gcry_mpi_point_t prod_g_i_b_i;
115
116   /**
117    * Product of the h_i^{b_i}
118    */
119   gcry_mpi_point_t prod_h_i_b_i;
120
121   /**
122    * Handle for our associated incoming CADET session, or NULL
123    * if we have not gotten one yet.
124    */
125   struct CadetIncomingSession *cadet;
126
127   /**
128    * How many elements will be supplied in total from the client.
129    */
130   uint32_t total;
131
132   /**
133    * Already transferred elements (received) for multipart
134    * messages from client. Always less than @e total.
135    */
136   uint32_t client_received_element_count;
137
138   /**
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.
142    */
143   uint32_t used_element_count;
144
145   /**
146    * Counts the number of values received from Alice by us.
147    * Always less than @e used_element_count.
148    */
149   uint32_t cadet_received_element_count;
150
151   /**
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.
156    */
157   enum GNUNET_SCALARPRODUCT_ResponseStatus status;
158
159   /**
160    * Are we already in #destroy_service_session()?
161    */
162   int in_destroy;
163
164 };
165
166
167 /**
168  * An incoming session from CADET.
169  */
170 struct CadetIncomingSession
171 {
172
173   /**
174    * Associated client session, or NULL.
175    */
176   struct BobServiceSession *s;
177
178   /**
179    * The CADET channel.
180    */
181   struct GNUNET_CADET_Channel *channel;
182
183   /**
184    * Originator's peer identity. (Only for diagnostics.)
185    */
186   struct GNUNET_PeerIdentity peer;
187
188   /**
189    * (hopefully) unique transaction ID
190    */
191   struct GNUNET_HashCode session_id;
192
193   /**
194    * The message queue for this channel.
195    */
196   struct GNUNET_MQ_Handle *cadet_mq;
197
198   /**
199    * Has this CADET session been added to the map yet?
200    * #GNUNET_YES if so, in which case @e session_id is
201    * the key.
202    */
203   int in_map;
204
205   /**
206    * Are we already in #destroy_cadet_session()?
207    */
208   int in_destroy;
209
210 };
211
212
213 /**
214  * GNUnet configuration handle
215  */
216 static const struct GNUNET_CONFIGURATION_Handle *cfg;
217
218 /**
219  * Map of `struct BobServiceSession`, by session keys.
220  */
221 static struct GNUNET_CONTAINER_MultiHashMap *client_sessions;
222
223 /**
224  * Map of `struct CadetIncomingSession`, by session keys.
225  */
226 static struct GNUNET_CONTAINER_MultiHashMap *cadet_sessions;
227
228 /**
229  * Handle to the CADET service.
230  */
231 static struct GNUNET_CADET_Handle *my_cadet;
232
233 /**
234  * Context for DLOG operations on a curve.
235  */
236 static struct GNUNET_CRYPTO_EccDlogContext *edc;
237
238
239
240 /**
241  * Finds a not terminated client session in the respective map based on
242  * session key.
243  *
244  * @param key the session key we want to search for
245  * @return the matching session, or NULL for none
246  */
247 static struct BobServiceSession *
248 find_matching_client_session (const struct GNUNET_HashCode *key)
249 {
250   return GNUNET_CONTAINER_multihashmap_get (client_sessions,
251                                             key);
252 }
253
254
255 /**
256  * Finds a CADET session in the respective map based on session key.
257  *
258  * @param key the session key we want to search for
259  * @return the matching session, or NULL for none
260  */
261 static struct CadetIncomingSession *
262 find_matching_cadet_session (const struct GNUNET_HashCode *key)
263 {
264   return GNUNET_CONTAINER_multihashmap_get (cadet_sessions,
265                                             key);
266 }
267
268
269 /**
270  * Callback used to free the elements in the map.
271  *
272  * @param cls NULL
273  * @param key key of the element
274  * @param value the value to free
275  */
276 static int
277 free_element_cb (void *cls,
278                  const struct GNUNET_HashCode *key,
279                  void *value)
280 {
281   struct GNUNET_SCALARPRODUCT_Element *element = value;
282
283   GNUNET_free (element);
284   return GNUNET_OK;
285 }
286
287
288 /**
289  * Destroy session state, we are done with it.
290  *
291  * @param session the session to free elements from
292  */
293 static void
294 destroy_cadet_session (struct CadetIncomingSession *s);
295
296
297 /**
298  * Destroy session state, we are done with it.
299  *
300  * @param session the session to free elements from
301  */
302 static void
303 destroy_service_session (struct BobServiceSession *s)
304 {
305   struct CadetIncomingSession *in;
306   unsigned int i;
307
308   if (GNUNET_YES == s->in_destroy)
309     return;
310   s->in_destroy = GNUNET_YES;
311   if (NULL != (in = s->cadet))
312   {
313     s->cadet = NULL;
314     destroy_cadet_session (in);
315   }
316   if (NULL != s->client_mq)
317   {
318     GNUNET_MQ_destroy (s->client_mq);
319     s->client_mq = NULL;
320   }
321   if (NULL != s->client)
322   {
323     GNUNET_SERVER_client_disconnect (s->client);
324     s->client = NULL;
325   }
326   GNUNET_assert (GNUNET_YES ==
327                  GNUNET_CONTAINER_multihashmap_remove (client_sessions,
328                                                        &s->session_id,
329                                                        s));
330   if (NULL != s->intersected_elements)
331   {
332     GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
333                                            &free_element_cb,
334                                            NULL);
335     GNUNET_CONTAINER_multihashmap_destroy (s->intersected_elements);
336     s->intersected_elements = NULL;
337   }
338   if (NULL != s->intersection_op)
339   {
340     GNUNET_SET_operation_cancel (s->intersection_op);
341     s->intersection_op = NULL;
342   }
343   if (NULL != s->intersection_set)
344   {
345     GNUNET_SET_destroy (s->intersection_set);
346     s->intersection_set = NULL;
347   }
348   if (NULL != s->sorted_elements)
349   {
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;
354   }
355   if (NULL != s->prod_g_i_b_i)
356   {
357     gcry_mpi_point_release (s->prod_g_i_b_i);
358     s->prod_g_i_b_i = NULL;
359   }
360   if (NULL != s->prod_g_i_b_i)
361   {
362     gcry_mpi_point_release (s->prod_h_i_b_i);
363     s->prod_h_i_b_i = NULL;
364   }
365   GNUNET_free (s);
366 }
367
368
369 /**
370  * Destroy incoming CADET session state, we are done with it.
371  *
372  * @param in the session to free elements from
373  */
374 static void
375 destroy_cadet_session (struct CadetIncomingSession *in)
376 {
377   struct BobServiceSession *s;
378
379   if (GNUNET_YES == in->in_destroy)
380     return;
381   in->in_destroy = GNUNET_YES;
382   if (NULL != (s = in->s))
383   {
384     in->s = NULL;
385     destroy_service_session (s);
386   }
387   if (GNUNET_YES == in->in_map)
388   {
389     GNUNET_assert (GNUNET_YES ==
390                    GNUNET_CONTAINER_multihashmap_remove (cadet_sessions,
391                                                          &in->session_id,
392                                                          in));
393     in->in_map = GNUNET_NO;
394   }
395   if (NULL != in->cadet_mq)
396   {
397     GNUNET_MQ_destroy (in->cadet_mq);
398     in->cadet_mq = NULL;
399   }
400   if (NULL != in->channel)
401   {
402     GNUNET_CADET_channel_destroy (in->channel);
403     in->channel = NULL;
404   }
405   GNUNET_free (in);
406 }
407
408
409 /**
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.
413  *
414  * @param session the associated client session to fail or succeed
415  */
416 static void
417 prepare_client_end_notification (struct BobServiceSession *session)
418 {
419   struct ClientResponseMessage *msg;
420   struct GNUNET_MQ_Envelope *e;
421
422   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
423               "Sending session-end notification with status %d to client for session %s\n",
424               session->status,
425               GNUNET_h2s (&session->session_id));
426   e = GNUNET_MQ_msg (msg,
427                      GNUNET_MESSAGE_TYPE_SCALARPRODUCT_RESULT);
428   msg->range = 0;
429   msg->product_length = htonl (0);
430   msg->status = htonl (session->status);
431   GNUNET_MQ_send (session->client_mq,
432                   e);
433 }
434
435
436 /**
437  * Function called whenever a channel is destroyed.  Should clean up
438  * any associated state.
439  *
440  * It must NOT call #GNUNET_CADET_channel_destroy() on the channel.
441  *
442  * @param cls closure (set from #GNUNET_CADET_connect())
443  * @param channel connection to the other end (henceforth invalid)
444  * @param channel_ctx place where local state associated
445  *                   with the channel is stored
446  */
447 static void
448 cb_channel_destruction (void *cls,
449                         const struct GNUNET_CADET_Channel *channel,
450                         void *channel_ctx)
451 {
452   struct CadetIncomingSession *in = channel_ctx;
453   struct BobServiceSession *s;
454
455   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
456               "Peer disconnected, terminating session %s with peer %s\n",
457               GNUNET_h2s (&in->session_id),
458               GNUNET_i2s (&in->peer));
459   if (NULL != in->cadet_mq)
460   {
461     GNUNET_MQ_destroy (in->cadet_mq);
462     in->cadet_mq = NULL;
463   }
464   in->channel = NULL;
465   if (NULL != (s = in->s))
466   {
467     if (GNUNET_SCALARPRODUCT_STATUS_ACTIVE == s->status)
468     {
469       s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
470       prepare_client_end_notification (s);
471     }
472   }
473   destroy_cadet_session (in);
474 }
475
476
477 /**
478  * MQ finished giving our last message to CADET, now notify
479  * the client that we are finished.
480  */
481 static void
482 bob_cadet_done_cb (void *cls)
483 {
484   struct BobServiceSession *session = cls;
485
486   session->status = GNUNET_SCALARPRODUCT_STATUS_SUCCESS;
487   prepare_client_end_notification (session);
488 }
489
490
491 /**
492  * Bob generates the response message to be sent to Alice.
493  *
494  * @param s the associated requesting session with Alice
495  */
496 static void
497 transmit_bobs_cryptodata_message (struct BobServiceSession *s)
498 {
499   struct EccBobCryptodataMessage *msg;
500   struct GNUNET_MQ_Envelope *e;
501
502   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
503               "Sending response to Alice\n");
504   e = GNUNET_MQ_msg (msg,
505                      GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_BOB_CRYPTODATA);
506   msg->contained_element_count = htonl (2);
507   if (NULL != s->prod_g_i_b_i)
508     GNUNET_CRYPTO_ecc_point_to_bin (edc,
509                                     s->prod_g_i_b_i,
510                                     &msg->prod_g_i_b_i);
511   if (NULL != s->prod_h_i_b_i)
512     GNUNET_CRYPTO_ecc_point_to_bin (edc,
513                                     s->prod_h_i_b_i,
514                                     &msg->prod_h_i_b_i);
515   GNUNET_MQ_notify_sent (e,
516                          &bob_cadet_done_cb,
517                          s);
518   GNUNET_MQ_send (s->cadet->cadet_mq,
519                   e);
520 }
521
522
523 /**
524  * Iterator to copy over messages from the hash map
525  * into an array for sorting.
526  *
527  * @param cls the `struct BobServiceSession *`
528  * @param key the key (unused)
529  * @param value the `struct GNUNET_SCALARPRODUCT_Element *`
530  * TODO: code duplication with Alice!
531  */
532 static int
533 copy_element_cb (void *cls,
534                  const struct GNUNET_HashCode *key,
535                  void *value)
536 {
537   struct BobServiceSession *s = cls;
538   struct GNUNET_SCALARPRODUCT_Element *e = value;
539   gcry_mpi_t mval;
540   int64_t val;
541
542   mval = gcry_mpi_new (0);
543   val = (int64_t) GNUNET_ntohll (e->value);
544   if (0 > val)
545     gcry_mpi_sub_ui (mval, mval, -val);
546   else
547     gcry_mpi_add_ui (mval, mval, val);
548   s->sorted_elements [s->used_element_count].value = mval;
549   s->sorted_elements [s->used_element_count].key = &e->key;
550   s->used_element_count++;
551   return GNUNET_OK;
552 }
553
554
555 /**
556  * Compare two `struct MpiValue`s by key for sorting.
557  *
558  * @param a pointer to first `struct MpiValue *`
559  * @param b pointer to first `struct MpiValue *`
560  * @return -1 for a < b, 0 for a=b, 1 for a > b.
561  * TODO: code duplication with Alice!
562  */
563 static int
564 element_cmp (const void *a,
565              const void *b)
566 {
567   const struct MpiElement *ma = a;
568   const struct MpiElement *mb = b;
569
570   return GNUNET_CRYPTO_hash_cmp (ma->key,
571                                  mb->key);
572 }
573
574
575 /**
576  * Handle a multipart-chunk of a request from another service to
577  * calculate a scalarproduct with us.
578  *
579  * @param cls closure (set from #GNUNET_CADET_connect)
580  * @param channel connection to the other end
581  * @param channel_ctx place to store local state associated with the @a channel
582  * @param message the actual message
583  * @return #GNUNET_OK to keep the connection open,
584  *         #GNUNET_SYSERR to close it (signal serious error)
585  */
586 static int
587 handle_alices_cryptodata_message (void *cls,
588                                   struct GNUNET_CADET_Channel *channel,
589                                   void **channel_ctx,
590                                   const struct GNUNET_MessageHeader *message)
591 {
592   struct CadetIncomingSession *in = *channel_ctx;
593   struct BobServiceSession *s;
594   const struct EccAliceCryptodataMessage *msg;
595   const struct GNUNET_CRYPTO_EccPoint *payload;
596   uint32_t contained_elements;
597   size_t msg_length;
598   uint16_t msize;
599   unsigned int max;
600   unsigned int i;
601   const struct MpiElement *b_i;
602   gcry_mpi_point_t tmp;
603   gcry_mpi_point_t g_i;
604   gcry_mpi_point_t h_i;
605   gcry_mpi_point_t g_i_b_i;
606   gcry_mpi_point_t h_i_b_i;
607
608   /* sanity checks */
609   if (NULL == in)
610   {
611     GNUNET_break_op (0);
612     return GNUNET_SYSERR;
613   }
614   s = in->s;
615   if (NULL == s)
616   {
617     GNUNET_break_op (0);
618     return GNUNET_SYSERR;
619   }
620   /* sort our vector for the computation */
621   if (NULL == s->sorted_elements)
622   {
623     s->sorted_elements
624       = GNUNET_malloc (GNUNET_CONTAINER_multihashmap_size (s->intersected_elements) *
625                        sizeof (struct MpiElement));
626     s->used_element_count = 0;
627     GNUNET_CONTAINER_multihashmap_iterate (s->intersected_elements,
628                                            &copy_element_cb,
629                                            s);
630     qsort (s->sorted_elements,
631            s->used_element_count,
632            sizeof (struct MpiElement),
633            &element_cmp);
634   }
635
636   /* parse message */
637   msize = ntohs (message->size);
638   if (msize <= sizeof (struct EccAliceCryptodataMessage))
639   {
640     GNUNET_break_op (0);
641     return GNUNET_SYSERR;
642   }
643   msg = (const struct EccAliceCryptodataMessage *) message;
644   contained_elements = ntohl (msg->contained_element_count);
645   /* Our intersection may still be ongoing, but this is nevertheless
646      an upper bound on the required array size */
647   max = GNUNET_CONTAINER_multihashmap_size (s->intersected_elements);
648   msg_length = sizeof (struct EccAliceCryptodataMessage)
649     + contained_elements * sizeof (struct GNUNET_CRYPTO_EccPoint) * 2;
650   if ( (msize != msg_length) ||
651        (0 == contained_elements) ||
652        (contained_elements > UINT16_MAX) ||
653        (max < contained_elements + s->cadet_received_element_count) )
654   {
655     GNUNET_break_op (0);
656     return GNUNET_SYSERR;
657   }
658   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
659               "Received %u crypto values from Alice\n",
660               (unsigned int) contained_elements);
661   payload = (const struct GNUNET_CRYPTO_EccPoint *) &msg[1];
662
663   for (i=0;i<contained_elements;i++)
664   {
665     b_i = &s->sorted_elements[i + s->cadet_received_element_count];
666     g_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
667                                           &payload[i * 2]);
668     g_i_b_i = GNUNET_CRYPTO_ecc_pmul_mpi (edc,
669                                           g_i,
670                                           b_i->value);
671     gcry_mpi_point_release (g_i);
672     h_i = GNUNET_CRYPTO_ecc_bin_to_point (edc,
673                                           &payload[i * 2 + 1]);
674     h_i_b_i = GNUNET_CRYPTO_ecc_pmul_mpi (edc,
675                                           h_i,
676                                           b_i->value);
677     gcry_mpi_point_release (h_i);
678     if (0 == i + s->cadet_received_element_count)
679     {
680       /* first iteration, nothing to add */
681       s->prod_g_i_b_i = g_i_b_i;
682       s->prod_h_i_b_i = h_i_b_i;
683     }
684     else
685     {
686       /* further iterations, cummulate resulting value */
687       tmp = GNUNET_CRYPTO_ecc_add (edc,
688                                    s->prod_g_i_b_i,
689                                    g_i_b_i);
690       gcry_mpi_point_release (s->prod_g_i_b_i);
691       gcry_mpi_point_release (g_i_b_i);
692       s->prod_g_i_b_i = tmp;
693       tmp = GNUNET_CRYPTO_ecc_add (edc,
694                                    s->prod_h_i_b_i,
695                                    h_i_b_i);
696       gcry_mpi_point_release (s->prod_h_i_b_i);
697       gcry_mpi_point_release (h_i_b_i);
698       s->prod_h_i_b_i = tmp;
699     }
700   }
701   s->cadet_received_element_count += contained_elements;
702   if ( (s->cadet_received_element_count == max) &&
703        (NULL == s->intersection_op) )
704   {
705     /* intersection has finished also on our side, and
706        we got the full set, so we can proceed with the
707        CADET response(s) */
708     transmit_bobs_cryptodata_message (s);
709   }
710   GNUNET_CADET_receive_done (s->cadet->channel);
711   return GNUNET_OK;
712 }
713
714
715 /**
716  * Callback for set operation results. Called for each element
717  * that needs to be removed from the result set.
718  *
719  * @param cls closure with the `struct BobServiceSession`
720  * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
721  * @param status what has happened with the set intersection?
722  */
723 static void
724 cb_intersection_element_removed (void *cls,
725                                  const struct GNUNET_SET_Element *element,
726                                  enum GNUNET_SET_Status status)
727 {
728   struct BobServiceSession *s = cls;
729   struct GNUNET_SCALARPRODUCT_Element *se;
730
731   switch (status)
732   {
733   case GNUNET_SET_STATUS_OK:
734     /* this element has been removed from the set */
735     se = GNUNET_CONTAINER_multihashmap_get (s->intersected_elements,
736                                             element->data);
737     GNUNET_assert (NULL != se);
738     LOG (GNUNET_ERROR_TYPE_DEBUG,
739          "Removed element with key %s and value %lld\n",
740          GNUNET_h2s (&se->key),
741          (long long) GNUNET_ntohll (se->value));
742     GNUNET_assert (GNUNET_YES ==
743                    GNUNET_CONTAINER_multihashmap_remove (s->intersected_elements,
744                                                          element->data,
745                                                          se));
746     GNUNET_free (se);
747     return;
748   case GNUNET_SET_STATUS_DONE:
749     s->intersection_op = NULL;
750     GNUNET_break (NULL == s->intersection_set);
751     GNUNET_CADET_receive_done (s->cadet->channel);
752     LOG (GNUNET_ERROR_TYPE_DEBUG,
753          "Finished intersection, %d items remain\n",
754          GNUNET_CONTAINER_multihashmap_size (s->intersected_elements));
755     if (s->client_received_element_count ==
756         GNUNET_CONTAINER_multihashmap_size (s->intersected_elements))
757     {
758       /* CADET transmission from Alice is also already done,
759          start with our own reply */
760       transmit_bobs_cryptodata_message (s);
761     }
762     return;
763   case GNUNET_SET_STATUS_HALF_DONE:
764     /* unexpected for intersection */
765     GNUNET_break (0);
766     return;
767   case GNUNET_SET_STATUS_FAILURE:
768     /* unhandled status code */
769     LOG (GNUNET_ERROR_TYPE_DEBUG,
770          "Set intersection failed!\n");
771     s->intersection_op = NULL;
772     if (NULL != s->intersection_set)
773     {
774       GNUNET_SET_destroy (s->intersection_set);
775       s->intersection_set = NULL;
776     }
777     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
778     prepare_client_end_notification (s);
779     return;
780   default:
781     GNUNET_break (0);
782     return;
783   }
784 }
785
786
787 /**
788  * We've paired up a client session with an incoming CADET request.
789  * Initiate set intersection work.
790  *
791  * @param s client session to start intersection for
792  */
793 static void
794 start_intersection (struct BobServiceSession *s)
795 {
796   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
797               "Got session with key %s and %u elements, starting intersection.\n",
798               GNUNET_h2s (&s->session_id),
799               (unsigned int) s->total);
800
801   s->intersection_op
802     = GNUNET_SET_prepare (&s->cadet->peer,
803                           &s->session_id,
804                           NULL,
805                           GNUNET_SET_RESULT_REMOVED,
806                           &cb_intersection_element_removed,
807                           s);
808   if (GNUNET_OK !=
809       GNUNET_SET_commit (s->intersection_op,
810                          s->intersection_set))
811   {
812     GNUNET_break (0);
813     s->status = GNUNET_SCALARPRODUCT_STATUS_FAILURE;
814     prepare_client_end_notification (s);
815     return;
816   }
817   GNUNET_SET_destroy (s->intersection_set);
818   s->intersection_set = NULL;
819 }
820
821
822 /**
823  * Handle a request from Alice to calculate a scalarproduct with us (Bob).
824  *
825  * @param cls closure (set from #GNUNET_CADET_connect)
826  * @param channel connection to the other end
827  * @param channel_ctx place to store the `struct CadetIncomingSession *`
828  * @param message the actual message
829  * @return #GNUNET_OK to keep the connection open,
830  *         #GNUNET_SYSERR to close it (signal serious error)
831  */
832 static int
833 handle_alices_computation_request (void *cls,
834                                    struct GNUNET_CADET_Channel *channel,
835                                    void **channel_ctx,
836                                    const struct GNUNET_MessageHeader *message)
837 {
838   struct CadetIncomingSession *in = *channel_ctx;
839   struct BobServiceSession *s;
840   const struct EccServiceRequestMessage *msg;
841
842   msg = (const struct EccServiceRequestMessage *) message;
843   if (GNUNET_YES == in->in_map)
844   {
845     GNUNET_break_op (0);
846     return GNUNET_SYSERR;
847   }
848   if (NULL != find_matching_cadet_session (&msg->session_id))
849   {
850     /* not unique, got one like this already */
851     GNUNET_break_op (0);
852     return GNUNET_SYSERR;
853   }
854   in->session_id = msg->session_id;
855   GNUNET_assert (GNUNET_YES ==
856                  GNUNET_CONTAINER_multihashmap_put (cadet_sessions,
857                                                     &in->session_id,
858                                                     in,
859                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
860   s = find_matching_client_session (&in->session_id);
861   if (NULL == s)
862   {
863     /* no client waiting for this request, wait for client */
864     return GNUNET_OK;
865   }
866   GNUNET_assert (NULL == s->cadet);
867   /* pair them up */
868   in->s = s;
869   s->cadet = in;
870   if (s->client_received_element_count == s->total)
871     start_intersection (s);
872   return GNUNET_OK;
873 }
874
875
876 /**
877  * Function called for inbound channels on Bob's end.  Does some
878  * preliminary initialization, more happens after we get Alice's first
879  * message.
880  *
881  * @param cls closure
882  * @param channel new handle to the channel
883  * @param initiator peer that started the channel
884  * @param port unused
885  * @param options unused
886  * @return session associated with the channel
887  */
888 static void *
889 cb_channel_incoming (void *cls,
890                      struct GNUNET_CADET_Channel *channel,
891                      const struct GNUNET_PeerIdentity *initiator,
892                      uint32_t port,
893                      enum GNUNET_CADET_ChannelOption options)
894 {
895   struct CadetIncomingSession *in;
896
897   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
898               "New incoming channel from peer %s.\n",
899               GNUNET_i2s (initiator));
900   in = GNUNET_new (struct CadetIncomingSession);
901   in->peer = *initiator;
902   in->channel = channel;
903   in->cadet_mq = GNUNET_CADET_mq_create (in->channel);
904   return in;
905 }
906
907
908 /**
909  * We're receiving additional set data. Add it to our
910  * set and if we are done, initiate the transaction.
911  *
912  * @param cls closure
913  * @param client identification of the client
914  * @param message the actual message
915  */
916 static void
917 GSS_handle_bob_client_message_multipart (void *cls,
918                                          struct GNUNET_SERVER_Client *client,
919                                          const struct GNUNET_MessageHeader *message)
920 {
921   const struct ComputationBobCryptodataMultipartMessage * msg;
922   struct BobServiceSession *s;
923   uint32_t contained_count;
924   const struct GNUNET_SCALARPRODUCT_Element *elements;
925   uint32_t i;
926   uint16_t msize;
927   struct GNUNET_SET_Element set_elem;
928   struct GNUNET_SCALARPRODUCT_Element *elem;
929
930   s = GNUNET_SERVER_client_get_user_context (client,
931                                              struct BobServiceSession);
932   if (NULL == s)
933   {
934     /* session needs to already exist */
935     GNUNET_break (0);
936     GNUNET_SERVER_receive_done (client,
937                                 GNUNET_SYSERR);
938     return;
939   }
940   msize = ntohs (message->size);
941   if (msize < sizeof (struct ComputationBobCryptodataMultipartMessage))
942   {
943     GNUNET_break (0);
944     GNUNET_SERVER_receive_done (client,
945                                 GNUNET_SYSERR);
946     return;
947   }
948   msg = (const struct ComputationBobCryptodataMultipartMessage *) message;
949   contained_count = ntohl (msg->element_count_contained);
950
951   if ( (msize != (sizeof (struct ComputationBobCryptodataMultipartMessage) +
952                   contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) ||
953        (0 == contained_count) ||
954        (UINT16_MAX < contained_count) ||
955        (s->total == s->client_received_element_count) ||
956        (s->total < s->client_received_element_count + contained_count) )
957   {
958     GNUNET_break_op (0);
959     GNUNET_SERVER_receive_done (client,
960                                 GNUNET_SYSERR);
961     return;
962   }
963   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
964   for (i = 0; i < contained_count; i++)
965   {
966     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
967     memcpy (elem,
968             &elements[i],
969             sizeof (struct GNUNET_SCALARPRODUCT_Element));
970     if (GNUNET_SYSERR ==
971         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
972                                            &elem->key,
973                                            elem,
974                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
975     {
976       GNUNET_break (0);
977       GNUNET_free (elem);
978       continue;
979     }
980     set_elem.data = &elem->key;
981     set_elem.size = sizeof (elem->key);
982     set_elem.element_type = 0;
983     GNUNET_SET_add_element (s->intersection_set,
984                             &set_elem,
985                             NULL, NULL);
986   }
987   s->client_received_element_count += contained_count;
988   GNUNET_SERVER_receive_done (client,
989                               GNUNET_OK);
990   if (s->total != s->client_received_element_count)
991   {
992     /* more to come */
993     return;
994   }
995   if (NULL == s->cadet)
996   {
997     /* no Alice waiting for this request, wait for Alice */
998     return;
999   }
1000   start_intersection (s);
1001 }
1002
1003
1004 /**
1005  * Handler for Bob's a client request message.  Bob is in the response
1006  * role, keep the values + session and waiting for a matching session
1007  * or process a waiting request from Alice.
1008  *
1009  * @param cls closure
1010  * @param client identification of the client
1011  * @param message the actual message
1012  */
1013 static void
1014 GSS_handle_bob_client_message (void *cls,
1015                                struct GNUNET_SERVER_Client *client,
1016                                const struct GNUNET_MessageHeader *message)
1017 {
1018   const struct BobComputationMessage *msg;
1019   struct BobServiceSession *s;
1020   struct CadetIncomingSession *in;
1021   uint32_t contained_count;
1022   uint32_t total_count;
1023   const struct GNUNET_SCALARPRODUCT_Element *elements;
1024   uint32_t i;
1025   struct GNUNET_SET_Element set_elem;
1026   struct GNUNET_SCALARPRODUCT_Element *elem;
1027   uint16_t msize;
1028
1029   s = GNUNET_SERVER_client_get_user_context (client,
1030                                              struct BobServiceSession);
1031   if (NULL != s)
1032   {
1033     /* only one concurrent session per client connection allowed,
1034        simplifies logic a lot... */
1035     GNUNET_break (0);
1036     GNUNET_SERVER_receive_done (client,
1037                                 GNUNET_SYSERR);
1038     return;
1039   }
1040   msize = ntohs (message->size);
1041   if (msize < sizeof (struct BobComputationMessage))
1042   {
1043     GNUNET_break (0);
1044     GNUNET_SERVER_receive_done (client,
1045                                 GNUNET_SYSERR);
1046     return;
1047   }
1048   msg = (const struct BobComputationMessage *) message;
1049   total_count = ntohl (msg->element_count_total);
1050   contained_count = ntohl (msg->element_count_contained);
1051   if ( (0 == total_count) ||
1052        (0 == contained_count) ||
1053        (UINT16_MAX < contained_count) ||
1054        (msize != (sizeof (struct BobComputationMessage) +
1055                   contained_count * sizeof (struct GNUNET_SCALARPRODUCT_Element))) )
1056   {
1057     GNUNET_break_op (0);
1058     GNUNET_SERVER_receive_done (client,
1059                                 GNUNET_SYSERR);
1060     return;
1061   }
1062   if (NULL != find_matching_client_session (&msg->session_key))
1063   {
1064     GNUNET_break (0);
1065     GNUNET_SERVER_receive_done (client,
1066                                 GNUNET_SYSERR);
1067     return;
1068   }
1069
1070   s = GNUNET_new (struct BobServiceSession);
1071   s->status = GNUNET_SCALARPRODUCT_STATUS_ACTIVE;
1072   s->client = client;
1073   s->client_mq = GNUNET_MQ_queue_for_server_client (client);
1074   s->total = total_count;
1075   s->client_received_element_count = contained_count;
1076   s->session_id = msg->session_key;
1077   GNUNET_break (GNUNET_YES ==
1078                 GNUNET_CONTAINER_multihashmap_put (client_sessions,
1079                                                    &s->session_id,
1080                                                    s,
1081                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1082   elements = (const struct GNUNET_SCALARPRODUCT_Element *) &msg[1];
1083   s->intersected_elements = GNUNET_CONTAINER_multihashmap_create (s->total,
1084                                                                   GNUNET_YES);
1085   s->intersection_set = GNUNET_SET_create (cfg,
1086                                            GNUNET_SET_OPERATION_INTERSECTION);
1087   for (i = 0; i < contained_count; i++)
1088   {
1089     if (0 == GNUNET_ntohll (elements[i].value))
1090       continue;
1091     elem = GNUNET_new (struct GNUNET_SCALARPRODUCT_Element);
1092     memcpy (elem,
1093             &elements[i],
1094             sizeof (struct GNUNET_SCALARPRODUCT_Element));
1095     if (GNUNET_SYSERR ==
1096         GNUNET_CONTAINER_multihashmap_put (s->intersected_elements,
1097                                            &elem->key,
1098                                            elem,
1099                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1100     {
1101       GNUNET_break (0);
1102       GNUNET_free (elem);
1103       continue;
1104     }
1105     set_elem.data = &elem->key;
1106     set_elem.size = sizeof (elem->key);
1107     set_elem.element_type = 0;
1108     GNUNET_SET_add_element (s->intersection_set,
1109                             &set_elem,
1110                             NULL, NULL);
1111     s->used_element_count++;
1112   }
1113   GNUNET_SERVER_client_set_user_context (client,
1114                                          s);
1115   GNUNET_SERVER_receive_done (client,
1116                               GNUNET_YES);
1117   if (s->total != s->client_received_element_count)
1118   {
1119     /* multipart msg */
1120     return;
1121   }
1122   in = find_matching_cadet_session (&s->session_id);
1123   if (NULL == in)
1124   {
1125     /* nothing yet, wait for Alice */
1126     return;
1127   }
1128   GNUNET_assert (NULL == in->s);
1129   /* pair them up */
1130   in->s = s;
1131   s->cadet = in;
1132   start_intersection (s);
1133 }
1134
1135
1136 /**
1137  * Task run during shutdown.
1138  *
1139  * @param cls unused
1140  * @param tc unused
1141  */
1142 static void
1143 shutdown_task (void *cls,
1144                const struct GNUNET_SCHEDULER_TaskContext *tc)
1145 {
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)
1150   {
1151     GNUNET_CADET_disconnect (my_cadet);
1152     my_cadet = NULL;
1153   }
1154   if (NULL != edc)
1155   {
1156     GNUNET_CRYPTO_ecc_dlog_release (edc);
1157     edc = NULL;
1158   }
1159   GNUNET_CONTAINER_multihashmap_destroy (client_sessions);
1160   client_sessions = NULL;
1161   GNUNET_CONTAINER_multihashmap_destroy (cadet_sessions);
1162   cadet_sessions = NULL;
1163 }
1164
1165
1166 /**
1167  * A client disconnected.
1168  *
1169  * Remove the associated session(s), release data structures
1170  * and cancel pending outgoing transmissions to the client.
1171  *
1172  * @param cls closure, NULL
1173  * @param client identification of the client
1174  */
1175 static void
1176 handle_client_disconnect (void *cls,
1177                           struct GNUNET_SERVER_Client *client)
1178 {
1179   struct BobServiceSession *s;
1180
1181   if (NULL == client)
1182     return;
1183   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1184               "Client disconnected from us.\n",
1185               client);
1186   s = GNUNET_SERVER_client_get_user_context (client,
1187                                              struct BobServiceSession);
1188   if (NULL == s)
1189     return;
1190   s->client = NULL;
1191   destroy_service_session (s);
1192 }
1193
1194
1195 /**
1196  * Initialization of the program and message handlers
1197  *
1198  * @param cls closure
1199  * @param server the initialized server
1200  * @param c configuration to use
1201  */
1202 static void
1203 run (void *cls,
1204      struct GNUNET_SERVER_Handle *server,
1205      const struct GNUNET_CONFIGURATION_Handle *c)
1206 {
1207   static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1208     { &GSS_handle_bob_client_message, NULL,
1209       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_TO_BOB,
1210       0},
1211     { &GSS_handle_bob_client_message_multipart, NULL,
1212       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_CLIENT_MUTLIPART_BOB,
1213       0},
1214     { NULL, NULL, 0, 0}
1215   };
1216   static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1217     { &handle_alices_computation_request,
1218       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_SESSION_INITIALIZATION,
1219       sizeof (struct EccServiceRequestMessage) },
1220     { &handle_alices_cryptodata_message,
1221       GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_ALICE_CRYPTODATA,
1222       0},
1223     { NULL, 0, 0}
1224   };
1225   static const uint32_t ports[] = {
1226     GNUNET_APPLICATION_TYPE_SCALARPRODUCT_ECC,
1227     0
1228   };
1229
1230   cfg = c;
1231   /* We don't really do DLOG, so we can setup with very minimal resources */
1232   edc = GNUNET_CRYPTO_ecc_dlog_prepare (4 /* max value */,
1233                                         2 /* RAM */);
1234
1235   GNUNET_SERVER_add_handlers (server,
1236                               server_handlers);
1237   GNUNET_SERVER_disconnect_notify (server,
1238                                    &handle_client_disconnect,
1239                                    NULL);
1240   client_sessions = GNUNET_CONTAINER_multihashmap_create (128,
1241                                                           GNUNET_YES);
1242   cadet_sessions = GNUNET_CONTAINER_multihashmap_create (128,
1243                                                          GNUNET_YES);
1244   my_cadet = GNUNET_CADET_connect (cfg, NULL,
1245                                    &cb_channel_incoming,
1246                                    &cb_channel_destruction,
1247                                    cadet_handlers,
1248                                    ports);
1249   if (NULL == my_cadet)
1250   {
1251     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1252                 _("Connect to CADET failed\n"));
1253     GNUNET_SCHEDULER_shutdown ();
1254     return;
1255   }
1256   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1257                                 &shutdown_task,
1258                                 NULL);
1259 }
1260
1261
1262 /**
1263  * The main function for the scalarproduct service.
1264  *
1265  * @param argc number of arguments from the command line
1266  * @param argv command line arguments
1267  * @return 0 ok, 1 on error
1268  */
1269 int
1270 main (int argc,
1271       char *const *argv)
1272 {
1273   return (GNUNET_OK ==
1274           GNUNET_SERVICE_run (argc, argv,
1275                               "scalarproduct-bob",
1276                               GNUNET_SERVICE_OPTION_NONE,
1277                               &run, NULL)) ? 0 : 1;
1278 }
1279
1280 /* end of gnunet-service-scalarproduct-ecc_bob.c */