fs_test_lib.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2010, 2011, 2012 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 fs/fs_test_lib.c
  18. * @brief library routines for testing FS publishing and downloading;
  19. * this code is limited to flat files
  20. * and no keywords (those functions can be tested with
  21. * single-peer setups; this is for testing routing).
  22. * @author Christian Grothoff
  23. */
  24. #include "platform.h"
  25. #include "fs_api.h"
  26. #include "fs_test_lib.h"
  27. #define CONTENT_LIFETIME GNUNET_TIME_UNIT_HOURS
  28. /**
  29. * Handle for a publishing operation started for testing FS.
  30. */
  31. struct TestPublishOperation
  32. {
  33. /**
  34. * Handle for the operation to connect to the peer's 'fs' service.
  35. */
  36. struct GNUNET_TESTBED_Operation *fs_op;
  37. /**
  38. * Handle to the file sharing context using this daemon.
  39. */
  40. struct GNUNET_FS_Handle *fs;
  41. /**
  42. * Function to call when upload is done.
  43. */
  44. GNUNET_FS_TEST_UriContinuation publish_cont;
  45. /**
  46. * Closure for publish_cont.
  47. */
  48. void *publish_cont_cls;
  49. /**
  50. * Task to abort publishing (timeout).
  51. */
  52. struct GNUNET_SCHEDULER_Task *publish_timeout_task;
  53. /**
  54. * Seed for file generation.
  55. */
  56. uint32_t publish_seed;
  57. /**
  58. * Context for current publishing operation.
  59. */
  60. struct GNUNET_FS_PublishContext *publish_context;
  61. /**
  62. * Result URI.
  63. */
  64. struct GNUNET_FS_Uri *publish_uri;
  65. /**
  66. * Name of the temporary file used, or NULL for none.
  67. */
  68. char *publish_tmp_file;
  69. /**
  70. * Size of the file.
  71. */
  72. uint64_t size;
  73. /**
  74. * Anonymity level used.
  75. */
  76. uint32_t anonymity;
  77. /**
  78. * Verbosity level of the current operation.
  79. */
  80. unsigned int verbose;
  81. /**
  82. * Are we testing indexing? (YES: index, NO: insert, SYSERR: simulate)
  83. */
  84. int do_index;
  85. };
  86. /**
  87. * Handle for a download operation started for testing FS.
  88. */
  89. struct TestDownloadOperation
  90. {
  91. /**
  92. * Handle for the operation to connect to the peer's 'fs' service.
  93. */
  94. struct GNUNET_TESTBED_Operation *fs_op;
  95. /**
  96. * Handle to the file sharing context using this daemon.
  97. */
  98. struct GNUNET_FS_Handle *fs;
  99. /**
  100. * Handle to the daemon via testing.
  101. */
  102. struct GNUNET_TESTING_Daemon *daemon;
  103. /**
  104. * Function to call when download is done.
  105. */
  106. GNUNET_SCHEDULER_TaskCallback download_cont;
  107. /**
  108. * Closure for download_cont.
  109. */
  110. void *download_cont_cls;
  111. /**
  112. * URI to download.
  113. */
  114. struct GNUNET_FS_Uri *uri;
  115. /**
  116. * Task to abort downloading (timeout).
  117. */
  118. struct GNUNET_SCHEDULER_Task *download_timeout_task;
  119. /**
  120. * Context for current download operation.
  121. */
  122. struct GNUNET_FS_DownloadContext *download_context;
  123. /**
  124. * Size of the file.
  125. */
  126. uint64_t size;
  127. /**
  128. * Anonymity level used.
  129. */
  130. uint32_t anonymity;
  131. /**
  132. * Seed for download verification.
  133. */
  134. uint32_t download_seed;
  135. /**
  136. * Verbosity level of the current operation.
  137. */
  138. unsigned int verbose;
  139. };
  140. /**
  141. * Task scheduled to report on the completion of our publish operation.
  142. *
  143. * @param cls the publish operation context
  144. * @param tc scheduler context (unused)
  145. */
  146. static void
  147. report_uri (void *cls)
  148. {
  149. struct TestPublishOperation *po = cls;
  150. GNUNET_FS_publish_stop (po->publish_context);
  151. GNUNET_TESTBED_operation_done (po->fs_op);
  152. po->publish_cont (po->publish_cont_cls,
  153. po->publish_uri,
  154. (GNUNET_YES == po->do_index)
  155. ? po->publish_tmp_file
  156. : NULL);
  157. GNUNET_FS_uri_destroy (po->publish_uri);
  158. if ((GNUNET_YES != po->do_index) &&
  159. (NULL != po->publish_tmp_file))
  160. (void) GNUNET_DISK_directory_remove (po->publish_tmp_file);
  161. GNUNET_free_non_null (po->publish_tmp_file);
  162. GNUNET_free (po);
  163. }
  164. /**
  165. * Task scheduled to run when publish operation times out.
  166. *
  167. * @param cls the publish operation context
  168. */
  169. static void
  170. publish_timeout (void *cls)
  171. {
  172. struct TestPublishOperation *po = cls;
  173. po->publish_timeout_task = NULL;
  174. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  175. "Timeout while trying to publish data\n");
  176. GNUNET_TESTBED_operation_done (po->fs_op);
  177. GNUNET_FS_publish_stop (po->publish_context);
  178. po->publish_cont (po->publish_cont_cls, NULL, NULL);
  179. (void) GNUNET_DISK_directory_remove (po->publish_tmp_file);
  180. GNUNET_free_non_null (po->publish_tmp_file);
  181. GNUNET_free (po);
  182. }
  183. /**
  184. * Progress callback for file-sharing events while publishing.
  185. *
  186. * @param cls the publish operation context
  187. * @param info information about the event
  188. */
  189. static void *
  190. publish_progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info)
  191. {
  192. struct TestPublishOperation *po = cls;
  193. switch (info->status)
  194. {
  195. case GNUNET_FS_STATUS_PUBLISH_COMPLETED:
  196. GNUNET_SCHEDULER_cancel (po->publish_timeout_task);
  197. po->publish_timeout_task = NULL;
  198. po->publish_uri =
  199. GNUNET_FS_uri_dup (info->value.publish.specifics.completed.chk_uri);
  200. GNUNET_SCHEDULER_add_now (&report_uri,
  201. po);
  202. break;
  203. case GNUNET_FS_STATUS_PUBLISH_PROGRESS:
  204. if (po->verbose)
  205. GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Publishing at %llu/%llu bytes\n",
  206. (unsigned long long) info->value.publish.completed,
  207. (unsigned long long) info->value.publish.size);
  208. break;
  209. case GNUNET_FS_STATUS_PUBLISH_PROGRESS_DIRECTORY:
  210. break;
  211. case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS:
  212. if (po->verbose)
  213. GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Download at %llu/%llu bytes\n",
  214. (unsigned long long) info->value.download.completed,
  215. (unsigned long long) info->value.download.size);
  216. break;
  217. default:
  218. break;
  219. }
  220. return NULL;
  221. }
  222. /**
  223. * Generate test data for publishing test.
  224. *
  225. * @param cls pointer to uint32_t with publishing seed
  226. * @param offset offset to generate data for
  227. * @param max maximum number of bytes to generate
  228. * @param buf where to write generated data
  229. * @param emsg where to store error message (unused)
  230. * @return number of bytes written to buf
  231. */
  232. static size_t
  233. file_generator (void *cls,
  234. uint64_t offset,
  235. size_t max,
  236. void *buf,
  237. char **emsg)
  238. {
  239. uint32_t *publish_seed = cls;
  240. uint64_t pos;
  241. uint8_t *cbuf = buf;
  242. int mod;
  243. if (emsg != NULL)
  244. *emsg = NULL;
  245. if (buf == NULL)
  246. return 0;
  247. for (pos = 0; pos < 8; pos++)
  248. cbuf[pos] = (uint8_t) (offset >> pos * 8);
  249. for (pos = 8; pos < max; pos++)
  250. {
  251. mod = (255 - (offset / 1024 / 32));
  252. if (mod == 0)
  253. mod = 1;
  254. cbuf[pos] = (uint8_t) ((offset * (*publish_seed)) % mod);
  255. }
  256. return max;
  257. }
  258. /**
  259. * Connect adapter for publishing operation.
  260. *
  261. * @param cls the 'struct TestPublishOperation'
  262. * @param cfg configuration of the peer to connect to; will be available until
  263. * GNUNET_TESTBED_operation_done() is called on the operation returned
  264. * from GNUNET_TESTBED_service_connect()
  265. * @return service handle to return in 'op_result', NULL on error
  266. */
  267. static void *
  268. publish_connect_adapter (void *cls,
  269. const struct GNUNET_CONFIGURATION_Handle *cfg)
  270. {
  271. struct TestPublishOperation *po = cls;
  272. return GNUNET_FS_start (cfg,
  273. "fs-test-publish",
  274. &publish_progress_cb, po,
  275. GNUNET_FS_FLAGS_NONE,
  276. GNUNET_FS_OPTIONS_END);
  277. }
  278. /**
  279. * Adapter function called to destroy connection to file-sharing service.
  280. *
  281. * @param cls the 'struct GNUNET_FS_Handle'
  282. * @param op_result unused (different for publish/download!)
  283. */
  284. static void
  285. fs_disconnect_adapter (void *cls,
  286. void *op_result)
  287. {
  288. struct GNUNET_FS_Handle *fs = op_result;
  289. GNUNET_FS_stop (fs);
  290. }
  291. /**
  292. * Callback to be called when testbed has connected to the fs service
  293. *
  294. * @param cls the 'struct TestPublishOperation'
  295. * @param op the operation that has been finished
  296. * @param ca_result the 'struct GNUNET_FS_Handle ' (NULL on error)
  297. * @param emsg error message in case the operation has failed; will be NULL if
  298. * operation has executed successfully.
  299. */
  300. static void
  301. publish_fs_connect_complete_cb (void *cls,
  302. struct GNUNET_TESTBED_Operation *op,
  303. void *ca_result,
  304. const char *emsg)
  305. {
  306. struct TestPublishOperation *po = cls;
  307. struct GNUNET_FS_FileInformation *fi;
  308. struct GNUNET_DISK_FileHandle *fh;
  309. char *em;
  310. uint64_t off;
  311. char buf[DBLOCK_SIZE];
  312. size_t bsize;
  313. struct GNUNET_FS_BlockOptions bo;
  314. if (NULL == ca_result)
  315. {
  316. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  317. "Failed to connect to FS for publishing: %s\n", emsg);
  318. po->publish_cont (po->publish_cont_cls,
  319. NULL, NULL);
  320. GNUNET_TESTBED_operation_done (po->fs_op);
  321. GNUNET_free (po);
  322. return;
  323. }
  324. po->fs = ca_result;
  325. bo.expiration_time = GNUNET_TIME_relative_to_absolute (CONTENT_LIFETIME);
  326. bo.anonymity_level = po->anonymity;
  327. bo.content_priority = 42;
  328. bo.replication_level = 1;
  329. if (GNUNET_YES == po->do_index)
  330. {
  331. po->publish_tmp_file = GNUNET_DISK_mktemp ("fs-test-publish-index");
  332. GNUNET_assert (po->publish_tmp_file != NULL);
  333. fh = GNUNET_DISK_file_open (po->publish_tmp_file,
  334. GNUNET_DISK_OPEN_WRITE
  335. | GNUNET_DISK_OPEN_CREATE,
  336. GNUNET_DISK_PERM_USER_READ
  337. | GNUNET_DISK_PERM_USER_WRITE);
  338. GNUNET_assert (NULL != fh);
  339. off = 0;
  340. while (off < po->size)
  341. {
  342. bsize = GNUNET_MIN (sizeof(buf), po->size - off);
  343. emsg = NULL;
  344. GNUNET_assert (bsize == file_generator (&po->publish_seed, off, bsize,
  345. buf, &em));
  346. GNUNET_assert (em == NULL);
  347. GNUNET_assert (bsize == GNUNET_DISK_file_write (fh, buf, bsize));
  348. off += bsize;
  349. }
  350. GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
  351. fi = GNUNET_FS_file_information_create_from_file (po->fs, po,
  352. po->publish_tmp_file,
  353. NULL, NULL, po->do_index,
  354. &bo);
  355. GNUNET_assert (NULL != fi);
  356. }
  357. else
  358. {
  359. fi = GNUNET_FS_file_information_create_from_reader (po->fs, po,
  360. po->size,
  361. &file_generator,
  362. &po->publish_seed,
  363. NULL, NULL,
  364. po->do_index, &bo);
  365. GNUNET_assert (NULL != fi);
  366. }
  367. po->publish_context =
  368. GNUNET_FS_publish_start (po->fs, fi, NULL, NULL, NULL,
  369. GNUNET_FS_PUBLISH_OPTION_NONE);
  370. }
  371. /**
  372. * Publish a file at the given peer.
  373. *
  374. * @param peer where to publish
  375. * @param timeout if this operation cannot be completed within the
  376. * given period, call the continuation with an error code
  377. * @param anonymity option for publication
  378. * @param do_index GNUNET_YES for index, GNUNET_NO for insertion,
  379. * GNUNET_SYSERR for simulation
  380. * @param size size of the file to publish
  381. * @param seed seed to use for file generation
  382. * @param verbose how verbose to be in reporting
  383. * @param cont function to call when done
  384. * @param cont_cls closure for cont
  385. */
  386. void
  387. GNUNET_FS_TEST_publish (struct GNUNET_TESTBED_Peer *peer,
  388. struct GNUNET_TIME_Relative timeout, uint32_t anonymity,
  389. int do_index, uint64_t size, uint32_t seed,
  390. unsigned int verbose,
  391. GNUNET_FS_TEST_UriContinuation cont, void *cont_cls)
  392. {
  393. struct TestPublishOperation *po;
  394. po = GNUNET_new (struct TestPublishOperation);
  395. po->publish_cont = cont;
  396. po->publish_cont_cls = cont_cls;
  397. po->publish_seed = seed;
  398. po->anonymity = anonymity;
  399. po->size = size;
  400. po->verbose = verbose;
  401. po->do_index = do_index;
  402. po->fs_op = GNUNET_TESTBED_service_connect (po,
  403. peer,
  404. "fs",
  405. &publish_fs_connect_complete_cb,
  406. po,
  407. &publish_connect_adapter,
  408. &fs_disconnect_adapter,
  409. po);
  410. po->publish_timeout_task =
  411. GNUNET_SCHEDULER_add_delayed (timeout, &publish_timeout, po);
  412. }
  413. /* ************************** download ************************ */
  414. /**
  415. * Task scheduled to run when download operation times out.
  416. *
  417. * @param cls the download operation context
  418. */
  419. static void
  420. download_timeout (void *cls)
  421. {
  422. struct TestDownloadOperation *dop = cls;
  423. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  424. "Timeout while trying to download file\n");
  425. dop->download_timeout_task = NULL;
  426. GNUNET_FS_download_stop (dop->download_context,
  427. GNUNET_YES);
  428. GNUNET_SCHEDULER_add_now (dop->download_cont,
  429. dop->download_cont_cls);
  430. GNUNET_TESTBED_operation_done (dop->fs_op);
  431. GNUNET_FS_uri_destroy (dop->uri);
  432. GNUNET_free (dop);
  433. }
  434. /**
  435. * Task scheduled to report on the completion of our download operation.
  436. *
  437. * @param cls the download operation context
  438. */
  439. static void
  440. report_success (void *cls)
  441. {
  442. struct TestDownloadOperation *dop = cls;
  443. GNUNET_FS_download_stop (dop->download_context,
  444. GNUNET_YES);
  445. GNUNET_SCHEDULER_add_now (dop->download_cont,
  446. dop->download_cont_cls);
  447. GNUNET_TESTBED_operation_done (dop->fs_op);
  448. GNUNET_FS_uri_destroy (dop->uri);
  449. GNUNET_free (dop);
  450. }
  451. /**
  452. * Progress callback for file-sharing events while downloading.
  453. *
  454. * @param cls the download operation context
  455. * @param info information about the event
  456. */
  457. static void *
  458. download_progress_cb (void *cls,
  459. const struct GNUNET_FS_ProgressInfo *info)
  460. {
  461. struct TestDownloadOperation *dop = cls;
  462. switch (info->status)
  463. {
  464. case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS:
  465. if (dop->verbose)
  466. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  467. "Download at %llu/%llu bytes\n",
  468. (unsigned long long) info->value.download.completed,
  469. (unsigned long long) info->value.download.size);
  470. break;
  471. case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED:
  472. GNUNET_SCHEDULER_cancel (dop->download_timeout_task);
  473. dop->download_timeout_task = NULL;
  474. GNUNET_SCHEDULER_add_now (&report_success, dop);
  475. break;
  476. case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE:
  477. case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE:
  478. break;
  479. /* FIXME: monitor data correctness during download progress */
  480. /* FIXME: do performance reports given sufficient verbosity */
  481. /* FIXME: advance timeout task to "immediate" on error */
  482. default:
  483. break;
  484. }
  485. return NULL;
  486. }
  487. /**
  488. * Connect adapter for download operation.
  489. *
  490. * @param cls the 'struct TestDownloadOperation'
  491. * @param cfg configuration of the peer to connect to; will be available until
  492. * GNUNET_TESTBED_operation_done() is called on the operation returned
  493. * from GNUNET_TESTBED_service_connect()
  494. * @return service handle to return in 'op_result', NULL on error
  495. */
  496. static void *
  497. download_connect_adapter (void *cls,
  498. const struct GNUNET_CONFIGURATION_Handle *cfg)
  499. {
  500. struct TestPublishOperation *po = cls;
  501. return GNUNET_FS_start (cfg,
  502. "fs-test-download",
  503. &download_progress_cb, po,
  504. GNUNET_FS_FLAGS_NONE,
  505. GNUNET_FS_OPTIONS_END);
  506. }
  507. /**
  508. * Callback to be called when testbed has connected to the fs service
  509. *
  510. * @param cls the 'struct TestPublishOperation'
  511. * @param op the operation that has been finished
  512. * @param ca_result the 'struct GNUNET_FS_Handle ' (NULL on error)
  513. * @param emsg error message in case the operation has failed; will be NULL if
  514. * operation has executed successfully.
  515. */
  516. static void
  517. download_fs_connect_complete_cb (void *cls,
  518. struct GNUNET_TESTBED_Operation *op,
  519. void *ca_result,
  520. const char *emsg)
  521. {
  522. struct TestDownloadOperation *dop = cls;
  523. dop->fs = ca_result;
  524. GNUNET_assert (NULL != dop->fs);
  525. dop->download_context =
  526. GNUNET_FS_download_start (dop->fs, dop->uri, NULL, NULL, NULL, 0, dop->size,
  527. dop->anonymity, GNUNET_FS_DOWNLOAD_OPTION_NONE,
  528. NULL, NULL);
  529. }
  530. /**
  531. * Perform test download.
  532. *
  533. * @param peer which peer to download from
  534. * @param timeout if this operation cannot be completed within the
  535. * given period, call the continuation with an error code
  536. * @param anonymity option for download
  537. * @param seed used for file validation
  538. * @param uri URI of file to download (CHK/LOC only)
  539. * @param verbose how verbose to be in reporting
  540. * @param cont function to call when done
  541. * @param cont_cls closure for cont
  542. */
  543. void
  544. GNUNET_FS_TEST_download (struct GNUNET_TESTBED_Peer *peer,
  545. struct GNUNET_TIME_Relative timeout,
  546. uint32_t anonymity, uint32_t seed,
  547. const struct GNUNET_FS_Uri *uri, unsigned int verbose,
  548. GNUNET_SCHEDULER_TaskCallback cont, void *cont_cls)
  549. {
  550. struct TestDownloadOperation *dop;
  551. dop = GNUNET_new (struct TestDownloadOperation);
  552. dop->uri = GNUNET_FS_uri_dup (uri);
  553. dop->size = GNUNET_FS_uri_chk_get_file_size (uri);
  554. dop->verbose = verbose;
  555. dop->anonymity = anonymity;
  556. dop->download_cont = cont;
  557. dop->download_cont_cls = cont_cls;
  558. dop->download_seed = seed;
  559. dop->fs_op = GNUNET_TESTBED_service_connect (dop,
  560. peer,
  561. "fs",
  562. &download_fs_connect_complete_cb,
  563. dop,
  564. &download_connect_adapter,
  565. &fs_disconnect_adapter,
  566. dop);
  567. dop->download_timeout_task =
  568. GNUNET_SCHEDULER_add_delayed (timeout, &download_timeout, dop);
  569. }
  570. /* end of fs_test_lib.c */