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