-again trying to delete old vectorproduct dir
[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
35 #define LOG(kind,...) GNUNET_log_from (kind, "gnunet-scalarproduct",__VA_ARGS__)
36 /**
37  * Option -p: destination peer identity for checking message-ids with
38  */
39 static char *input_peer_id = NULL;
40
41 /**
42  * Option -p: destination peer identity for checking message-ids with
43  */
44 static char *input_key = NULL;
45
46 /**
47  * Option -e: vector to calculate a scalarproduct with
48  */
49 static char *input_elements = NULL;
50
51 /**
52  * Option -m: message-ids to calculate a scalarproduct with
53  */
54 static char *input_mask = NULL;
55
56 /**
57  * the count of the messages sent to the service for processing
58  */
59 static unsigned short element_count;
60
61 /**
62  * the count of the mask bytes
63  */
64 unsigned short mask_length = 0;
65
66 /**
67  * the count of the number of mask bytes
68  */
69 unsigned short mask_bytes;
70
71 /**
72  * the array of converted message IDs to send to our service
73  */
74 static int32_t * elements = NULL;
75
76 /**
77  * the array of converted message IDs to send to our service
78  */
79 static unsigned char * mask = NULL;
80
81 /**
82  * information about the peer we are comparing with
83  */
84 struct GNUNET_PeerIdentity peer;
85
86 /**
87  * information about the peer we are comparing with
88  */
89 struct GNUNET_HashCode key;
90
91 /**
92  * Pointer to the GNUNET_SCALARPRODUCT_Handle
93  */
94 struct GNUNET_SCALARPRODUCT_Handle *handle;
95
96 /**
97  * Global return value
98  */
99 static int ret;
100
101 struct GNUNET_SCALARPRODUCT_TestCls
102 {
103   struct GNUNET_SCALARPRODUCT_Handle * h;
104 };
105
106 struct GNUNET_SCALARPRODUCT_TestCls test_cls;
107
108
109 /**
110  * Callback called if we are initiating a new computation session
111  * 
112  * @param cls unused
113  * @param status if our job was successfully processed 
114  */
115 static void
116 responder_callback (void *cls,
117                     const struct GNUNET_HashCode * key,
118                     enum GNUNET_SCALARPRODUCT_ResponseStatus status)
119 {
120   ret = -1;
121
122   switch (status)
123     {
124     case GNUNET_SCALARPRODUCT_Status_Success:
125       ret = 0;
126       LOG (GNUNET_ERROR_TYPE_INFO, "Session %s concluded.\n", GNUNET_h2s (key));
127       break;
128     case GNUNET_SCALARPRODUCT_Status_InvalidResponse:
129       LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: invalid response\n", GNUNET_h2s (key));
130       break;
131     case GNUNET_SCALARPRODUCT_Status_Timeout:
132       LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: timeout\n", GNUNET_h2s (key));
133       break;
134     case GNUNET_SCALARPRODUCT_Status_Failure:
135       LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: service failure\n", GNUNET_h2s (key));
136     case GNUNET_SCALARPRODUCT_Status_ServiceDisconnected:
137       LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: service disconnect!!\n", GNUNET_h2s (key));
138       break;
139     default:
140       LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: return code %d\n", GNUNET_h2s (key), (int) status);
141     }
142
143   GNUNET_SCALARPRODUCT_disconnect (handle);
144   GNUNET_SCHEDULER_shutdown ();
145 }
146
147
148 /**
149  * Callback called if we are initiating a new computation session
150  * 
151  * @param cls unused
152  * @param key unused
153  * @param peer unused
154  * @param status if our job was successfully processed 
155  * @param size size of the msg returned
156  * @param msg the response we got.
157  * @param type of the message received 
158  */
159 static void
160 requester_callback (void *cls,
161         const struct GNUNET_HashCode * key,
162         const struct GNUNET_PeerIdentity * peer,
163         enum GNUNET_SCALARPRODUCT_ResponseStatus status,
164         const struct GNUNET_SCALARPRODUCT_client_response *msg)
165 {
166   uint32_t product_len;
167   ret = -1;
168
169   switch (status)
170     {
171     case GNUNET_SCALARPRODUCT_Status_Success:
172       product_len = ntohl (msg->product_length);
173
174       LOG (GNUNET_ERROR_TYPE_INFO, "Session %s concluded.\n", GNUNET_h2s (key));
175
176       if (0 < product_len && NULL != &msg[1])
177         {
178           gcry_mpi_t result;
179           size_t read = 0;
180
181           if (0 != gcry_mpi_scan (&result, GCRYMPI_FMT_USG, &msg[1], product_len, &read))
182             LOG (GNUNET_ERROR_TYPE_ERROR, "Could not convert to mpi to value!\n");
183           else
184             {
185               unsigned char * buf;
186               gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buf, NULL, result);
187
188               printf ("Successfully computed result for session %s: %s\n", GNUNET_h2s (key), buf);
189               ret = 0;
190             }
191         }
192       else
193         { //currently not used, but if we get more info due to MESH we will need this
194           LOG (GNUNET_ERROR_TYPE_ERROR, "Service-side error in session %s, return code: %d\n", GNUNET_h2s (key), product_len);
195         }
196       break;
197     case GNUNET_SCALARPRODUCT_Status_InvalidResponse:
198       LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: invalid response\n", GNUNET_h2s (key));
199       break;
200     case GNUNET_SCALARPRODUCT_Status_Timeout:
201       LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: timeout\n", GNUNET_h2s (key));
202       break;
203     case GNUNET_SCALARPRODUCT_Status_Failure:
204       LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: service failure\n", GNUNET_h2s (key));
205     case GNUNET_SCALARPRODUCT_Status_ServiceDisconnected:
206       LOG (GNUNET_ERROR_TYPE_ERROR, "Disconnected from service.\n", GNUNET_h2s (key));
207       break;
208     default:
209       LOG (GNUNET_ERROR_TYPE_ERROR, "Session %s failed: return code %d\n", GNUNET_h2s (key), (int) status);
210     }
211   GNUNET_SCALARPRODUCT_disconnect (handle);
212   GNUNET_SCHEDULER_shutdown ();
213 }
214
215
216 /**
217  * Main function that will be run by the scheduler.
218  *
219  * @param cls closure
220  * @param args remaining command-line arguments
221  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
222  * @param cfg configuration
223  */
224 static void
225 run (void *cls,
226      char *const *args,
227      const char *cfgfile,
228      const struct GNUNET_CONFIGURATION_Handle *cfg)
229 {
230   char * begin = input_elements;
231   char * end;
232   int32_t element;
233   int i;
234   ret = -1;
235
236   if (NULL == input_elements)
237     {
238       FPRINTF (stderr, "%s", _ ("You must specify at least one message ID to check!\n"));
239       return;
240     }
241
242   if (NULL == input_key)
243     {
244       FPRINTF (stderr, "%s", _ ("This program needs a session identifier for comparing vectors.\n"));
245       return;
246     }
247
248   if (1 > strnlen (input_key, sizeof (struct GNUNET_HashCode)))
249     {
250       FPRINTF (stderr, _ ("Please give a session key for --input_key!\n"));
251       return;
252     }
253   GNUNET_CRYPTO_hash (input_key, strlen (input_key), &key);
254
255   if (input_peer_id && GNUNET_OK != GNUNET_CRYPTO_hash_from_string (input_peer_id,
256                                                                     (struct GNUNET_HashCode *) &peer))
257     {
258       FPRINTF (stderr, _ ("Tried to set initiator mode, as peer ID was given. "
259                           "However, `%s' is not a valid peer identifier.\n"),
260                input_peer_id);
261       return;
262     }
263
264   int exit_loop = 0;
265   /* Read input_elements_peer1, and put in elements_peer1 array */
266   do
267     {
268       unsigned int mcount = element_count;
269       //ignore empty rows of ,,,,,,
270       while (*begin == ',')
271         begin++;
272       // get the length of the current element and replace , with null
273       for (end = begin; *end && *end != ','; end++);
274
275       if (*end == '\0')
276         exit_loop = 1;
277
278       if (*end == ',')
279         *end = '\0';
280
281       if (1 != sscanf (begin, "%" SCNd32, &element))
282         {
283           FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
284           return;
285         }
286
287       GNUNET_array_append (elements, mcount, element);
288       element_count++;
289
290       begin = ++end;
291     }
292   while (!exit_loop);
293
294   GNUNET_assert (elements != NULL);
295   GNUNET_assert (element_count > 1);
296   mask_length = element_count / 8 + (element_count % 8 ? 1 : 0);
297   mask = GNUNET_malloc ((element_count / 8) + 2);
298
299   /* Read input_mask_peer1 and read in mask_peer1 array */
300   if (NULL != input_mask)
301     {
302       begin = input_mask;
303       unsigned short mask_count = 0;
304       int exit_loop = 0;
305
306       do
307         {
308           //ignore empty rows of ,,,,,,
309           while (* begin == ',')
310             begin++;
311           // get the length of the current element and replace , with null
312           // gnunet_ascii-armor uses base32, thus we can use , as separator!
313           for (end = begin; *end && *end != ','; end++);
314
315           if (*end == '\0')
316             exit_loop = 1;
317
318           if (*end == ',')
319             *end = '\0';
320
321           if (1 != sscanf (begin, "%" SCNd32, &element))
322             {
323               FPRINTF (stderr, _ ("Could not convert `%s' to int32_t.\n"), begin);
324               return;
325             }
326
327           GNUNET_assert (mask_count <= element_count);
328
329           if (element)
330             mask[mask_count / 8] = mask[mask_count / 8] | 1 << (mask_count % 8);
331
332           mask_count++;
333           begin = ++end;
334         }
335       while (!exit_loop);
336       // +1 to see if we would have more data, which would indicate malformed/superficial input
337       GNUNET_assert (mask_count == element_count);
338     }
339   else if (input_peer_id)
340     {
341       for (i = 0; i <= mask_length; i++)
342         mask[i] = UCHAR_MAX; // all 1's
343     }
344
345   handle = GNUNET_SCALARPRODUCT_connect (cfg);
346   if (handle == NULL)
347     {
348       FPRINTF (stderr, _ ("Could not connect to the GNUNET Vector Product Service\n"));
349       return;
350     }
351
352   test_cls.h = handle;
353
354   if (input_peer_id && !GNUNET_SCALARPRODUCT_request (handle,
355                                                       &key,
356                                                       &peer,
357                                                       element_count,
358                                                       mask_length,
359                                                       elements, mask,
360                                                       GNUNET_TIME_UNIT_MINUTES,
361                                                       &requester_callback,
362                                                       (void *) &test_cls))
363     return;
364   if ( !input_peer_id && !GNUNET_SCALARPRODUCT_prepare_response (handle,
365                                                    &key,
366                                                    element_count,
367                                                    elements,
368                                                    GNUNET_TIME_UNIT_MINUTES,
369                                                    &responder_callback,
370                                                    (void *) &test_cls))
371     return;
372
373   ret = 0;
374 }
375
376
377 /**
378  * The main function to the scalarproduct client.
379  *
380  * @param argc number of arguments from the command line
381  * @param argv command line arguments
382  * @return 0 ok, 1 on error
383  */
384 int
385 main (int argc, char *const *argv)
386 {
387   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
388     {'e', "elements", "\"val1,val2,...,valn\"",
389       gettext_noop ("A comma separated list of elements to compare as vector with our remote peer."),
390       1, &GNUNET_GETOPT_set_string, &input_elements},
391     {'m', "mask", "\"0,1,...,maskn\"",
392       gettext_noop ("A comma separated mask to select which elements should actually be compared."),
393       1, &GNUNET_GETOPT_set_string, &input_mask},
394     {'p', "peer", "PEERID",
395       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."),
396       1, &GNUNET_GETOPT_set_string, &input_peer_id},
397     {'k', "key", "TRANSACTION_ID",
398       gettext_noop ("Transaction ID shared with peer."),
399       1, &GNUNET_GETOPT_set_string, &input_key},
400     GNUNET_GETOPT_OPTION_END
401   };
402
403   return (GNUNET_OK ==
404           GNUNET_PROGRAM_run (argc,
405                               argv,
406                               "gnunet-scalarproduct",
407                               gettext_noop ("Calculate the Vectorproduct with a GNUnet peer."),
408                               options, &run, NULL)) ? ret : 1;
409 }
410