gnunet-scalarproduct.c 11 KB

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