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