gnunet-scalarproduct.c 10 KB

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