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