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