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