ftbfs
[oweals/gnunet.git] / src / scalarproduct / gnunet-scalarproduct.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2013, 2014 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      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20
21 /**
22  * @file scalarproduct/gnunet-scalarproduct.c
23  * @brief scalarproduct client
24  * @author Christian M. Fuchs
25  */
26 #define GCRYPT_NO_DEPRECATED
27 #include <gcrypt.h>
28 #include <inttypes.h>
29
30 #include "platform.h"
31 #include "gnunet_util_lib.h"
32 #include "gnunet_scalarproduct_service.h"
33 #include "gnunet_protocols.h"
34 #include "scalarproduct.h"
35
36 #define LOG(kind, ...) GNUNET_log_from (kind, "gnunet-scalarproduct", \
37                                         __VA_ARGS__)
38
39
40 /**
41  * the session key identifying this computation
42  */
43 static struct GNUNET_HashCode session_key;
44
45 /**
46  * PeerID we want to compute a scalar product with
47  */
48 static struct GNUNET_PeerIdentity peer_id;
49
50 /**
51  * Option -p: destination peer identity for checking message-ids with
52  */
53 static char *input_peer_id;
54
55 /**
56  * Option -p: destination peer identity for checking message-ids with
57  */
58 static char *input_session_key;
59
60 /**
61  * Option -e: vector to calculate a scalarproduct with
62  */
63 static char *input_elements;
64
65 /**
66  * Global return value
67  */
68 static int ret = -1;
69
70 /**
71  * our Scalarproduct Computation handle
72  */
73 static struct GNUNET_SCALARPRODUCT_ComputationHandle *computation;
74
75
76 /**
77  * Callback called if we are initiating a new computation session
78  *
79  * @param cls unused
80  * @param status if our job was successfully processed
81  */
82 static void
83 responder_callback (void *cls,
84                     enum GNUNET_SCALARPRODUCT_ResponseStatus status)
85 {
86   switch (status)
87   {
88   case GNUNET_SCALARPRODUCT_STATUS_SUCCESS:
89     ret = 0;
90     LOG (GNUNET_ERROR_TYPE_INFO,
91          "Session %s concluded.\n",
92          GNUNET_h2s (&session_key));
93     break;
94
95   case GNUNET_SCALARPRODUCT_STATUS_INVALID_RESPONSE:
96     LOG (GNUNET_ERROR_TYPE_ERROR,
97          "Session %s failed: invalid response\n",
98          GNUNET_h2s (&session_key));
99     break;
100
101   case GNUNET_SCALARPRODUCT_STATUS_FAILURE:
102     LOG (GNUNET_ERROR_TYPE_ERROR,
103          "Session %s failed: service failure\n",
104          GNUNET_h2s (&session_key));
105     break;
106
107   case GNUNET_SCALARPRODUCT_STATUS_DISCONNECTED:
108     LOG (GNUNET_ERROR_TYPE_ERROR,
109          "Session %s failed: service disconnect!\n",
110          GNUNET_h2s (&session_key));
111     break;
112
113   default:
114     LOG (GNUNET_ERROR_TYPE_ERROR,
115          "Session %s failed: return code %d\n",
116          GNUNET_h2s (&session_key),
117          status);
118   }
119   computation = NULL;
120   GNUNET_SCHEDULER_shutdown ();
121 }
122
123
124 /**
125  * Callback called if we are initiating a new computation session
126  *
127  * @param cls unused
128  * @param status if our job was successfully processed
129  * @param result the result in gnu/gcry MPI format
130  */
131 static void
132 requester_callback (void *cls,
133                     enum GNUNET_SCALARPRODUCT_ResponseStatus status,
134                     gcry_mpi_t result)
135 {
136   unsigned char *buf;
137   gcry_error_t rc;
138
139   switch (status)
140   {
141   case GNUNET_SCALARPRODUCT_STATUS_SUCCESS:
142     if (0 == (rc = gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buf, NULL, result)))
143     {
144       ret = 0;
145       fprintf (stdout,
146                "%s\n",
147                buf);
148       fflush (stdout);
149     }
150     else
151       LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
152                 "gcry_mpi_aprint",
153                 rc);
154     break;
155
156   case GNUNET_SCALARPRODUCT_STATUS_INVALID_RESPONSE:
157     LOG (GNUNET_ERROR_TYPE_ERROR,
158          "Session %s with peer %s failed: invalid response received\n",
159          GNUNET_h2s (&session_key),
160          GNUNET_i2s (&peer_id));
161     break;
162
163   case GNUNET_SCALARPRODUCT_STATUS_FAILURE:
164     LOG (GNUNET_ERROR_TYPE_ERROR,
165          "Session %s with peer %s failed: API failure\n",
166          GNUNET_h2s (&session_key),
167          GNUNET_i2s (&peer_id));
168     break;
169
170   case GNUNET_SCALARPRODUCT_STATUS_DISCONNECTED:
171     LOG (GNUNET_ERROR_TYPE_ERROR,
172          "Session %s with peer %s was disconnected from service.\n",
173          GNUNET_h2s (&session_key),
174          GNUNET_i2s (&peer_id));
175     break;
176
177   default:
178     LOG (GNUNET_ERROR_TYPE_ERROR,
179          "Session %s with peer %s failed: return code %d\n",
180          GNUNET_h2s (&session_key),
181          GNUNET_i2s (&peer_id),
182          status);
183   }
184   computation = NULL;
185   GNUNET_SCHEDULER_shutdown ();
186 }
187
188
189 /**
190  * Task run during shutdown.
191  *
192  * @param cls unused
193  * @param tc unused
194  */
195 static void
196 shutdown_task (void *cls)
197 {
198   if (NULL != computation)
199   {
200     GNUNET_SCALARPRODUCT_cancel (computation);
201     ret = 1;   /* aborted */
202   }
203 }
204
205
206 /**
207  * Main function that will be run by the scheduler.
208  *
209  * @param cls closure
210  * @param args remaining command-line arguments
211  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
212  * @param cfg configuration
213  */
214 static void
215 run (void *cls,
216      char *const *args,
217      const char *cfgfile,
218      const struct GNUNET_CONFIGURATION_Handle *cfg)
219 {
220   char *begin = input_elements;
221   char *end;
222   unsigned int i;
223   struct GNUNET_SCALARPRODUCT_Element *elements;
224   uint32_t element_count = 0;
225
226   if (NULL == input_elements)
227   {
228     LOG (GNUNET_ERROR_TYPE_ERROR,
229          _ ("You must specify at least one message ID to check!\n"));
230     return;
231   }
232   if ((NULL == input_session_key) ||
233       (0 == strlen (input_session_key)))
234   {
235     LOG (GNUNET_ERROR_TYPE_ERROR,
236          _ (
237            "This program needs a session identifier for comparing vectors.\n"));
238     return;
239   }
240   GNUNET_CRYPTO_hash (input_session_key,
241                       strlen (input_session_key),
242                       &session_key);
243   if ((NULL != input_peer_id) &&
244       (GNUNET_OK !=
245        GNUNET_CRYPTO_eddsa_public_key_from_string (input_peer_id,
246                                                    strlen (input_peer_id),
247                                                    &peer_id.public_key)))
248   {
249     LOG (GNUNET_ERROR_TYPE_ERROR,
250          _ ("Tried to set initiator mode, as peer ID was given. "
251             "However, `%s' is not a valid peer identifier.\n"),
252          input_peer_id);
253     return;
254   }
255   if (('\'' == *begin) &&
256       ('\'' == begin[strlen (begin) - 1]))
257   {
258     begin[strlen (begin) - 1] = '\0';
259     if (strlen (begin) > 0)
260       begin++;
261   }
262   for (end = begin; 0 != *end; end++)
263     if (*end == ';')
264       element_count++;
265   if (0 == element_count)
266   {
267     LOG (GNUNET_ERROR_TYPE_ERROR,
268          _ ("Need elements to compute the scalarproduct, got none.\n"));
269     return;
270   }
271
272   elements = GNUNET_malloc (sizeof(struct GNUNET_SCALARPRODUCT_Element)
273                             * element_count);
274
275   for (i = 0; i < element_count; i++)
276   {
277     struct GNUNET_SCALARPRODUCT_Element element;
278     char*separator = NULL;
279
280     /* get the length of the current key,value; tupel */
281     for (end = begin; *end != ';'; end++)
282       if (*end == ',')
283         separator = end;
284
285     /* final element */
286     if ((NULL == separator) ||
287         (begin == separator) ||
288         (separator == end - 1))
289     {
290       LOG (GNUNET_ERROR_TYPE_ERROR,
291            _ ("Malformed input, could not parse `%s'\n"),
292            begin);
293       GNUNET_free (elements);
294       return;
295     }
296     *separator = 0;
297     /* read the element's key */
298     GNUNET_CRYPTO_hash (begin,
299                         strlen (begin),
300                         &element.key);
301
302     /* read the element's value */
303     if (1 !=
304         sscanf (separator + 1,
305                 "%" SCNd64 ";",
306                 &element.value))
307     {
308       LOG (GNUNET_ERROR_TYPE_ERROR,
309            _ ("Could not convert `%s' to int64_t.\n"),
310            begin);
311       GNUNET_free (elements);
312       return;
313     }
314     element.value = GNUNET_htonll (element.value);
315     elements[i] = element;
316     begin = end + 1;
317   }
318
319   if (((NULL != input_peer_id) &&
320        (NULL == (computation
321                    = GNUNET_SCALARPRODUCT_start_computation (cfg,
322                                                              &session_key,
323                                                              &peer_id,
324                                                              elements,
325                                                              element_count,
326                                                              &requester_callback,
327                                                              NULL)))) ||
328       ((NULL == input_peer_id) &&
329        (NULL == (computation
330                    = GNUNET_SCALARPRODUCT_accept_computation (cfg,
331                                                               &session_key,
332                                                               elements,
333                                                               element_count,
334                                                               &
335                                                               responder_callback,
336                                                               NULL)))))
337   {
338     fprintf (stderr,
339              _ ("Failed to initiate computation, were all keys unique?\n"));
340     GNUNET_free (elements);
341     return;
342   }
343   GNUNET_free (elements);
344   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
345                                  NULL);
346   ret = 0;
347 }
348
349
350 /**
351  * The main function to the scalarproduct client.
352  *
353  * @param argc number of arguments from the command line
354  * @param argv command line arguments
355  * @return 0 ok, 1 on error
356  */
357 int
358 main (int argc, char *const *argv)
359 {
360   struct GNUNET_GETOPT_CommandLineOption options[] = {
361     GNUNET_GETOPT_option_string ('e',
362                                  "elements",
363                                  "\"key1,val1;key2,val2;...,keyn,valn;\"",
364                                  gettext_noop (
365                                    "A comma separated list of elements to compare as vector with our remote peer."),
366                                  &input_elements),
367
368     GNUNET_GETOPT_option_string ('e',
369                                  "elements",
370                                  "\"key1,val1;key2,val2;...,keyn,valn;\"",
371                                  gettext_noop (
372                                    "A comma separated list of elements to compare as vector with our remote peer."),
373                                  &input_elements),
374
375     GNUNET_GETOPT_option_string ('p',
376                                  "peer",
377                                  "PEERID",
378                                  gettext_noop (
379                                    "[Optional] peer to calculate our scalarproduct with. If this parameter is not given, the service will wait for a remote peer to compute the request."),
380                                  &input_peer_id),
381
382     GNUNET_GETOPT_option_string ('k',
383                                  "key",
384                                  "TRANSACTION_ID",
385                                  gettext_noop (
386                                    "Transaction ID shared with peer."),
387                                  &input_session_key),
388
389     GNUNET_GETOPT_OPTION_END
390   };
391
392   return (GNUNET_OK ==
393           GNUNET_PROGRAM_run (argc,
394                               argv,
395                               "gnunet-scalarproduct",
396                               gettext_noop (
397                                 "Calculate the Vectorproduct with a GNUnet peer."),
398                               options, &run, NULL)) ? ret : 1;
399 }
400
401
402 /* end of gnunet-scalarproduct.c */