fs_download.c 77 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2001-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_download.c
  18. * @brief download methods
  19. * @author Christian Grothoff
  20. */
  21. #include "platform.h"
  22. #include "gnunet_constants.h"
  23. #include "gnunet_fs_service.h"
  24. #include "fs_api.h"
  25. #include "fs_tree.h"
  26. /**
  27. * Determine if the given download (options and meta data) should cause
  28. * use to try to do a recursive download.
  29. */
  30. static int
  31. is_recursive_download (struct GNUNET_FS_DownloadContext *dc)
  32. {
  33. return (0 != (dc->options & GNUNET_FS_DOWNLOAD_OPTION_RECURSIVE)) &&
  34. ((GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (dc->meta)) ||
  35. ((NULL == dc->meta) &&
  36. ((NULL == dc->filename) ||
  37. ((strlen (dc->filename) >= strlen (GNUNET_FS_DIRECTORY_EXT)) &&
  38. (NULL != strstr (dc->filename + strlen (dc->filename)
  39. - strlen (GNUNET_FS_DIRECTORY_EXT),
  40. GNUNET_FS_DIRECTORY_EXT))))));
  41. }
  42. /**
  43. * We're storing the IBLOCKS after the DBLOCKS on disk (so that we
  44. * only have to truncate the file once we're done).
  45. *
  46. * Given the offset of a block (with respect to the DBLOCKS) and its
  47. * depth, return the offset where we would store this block in the
  48. * file.
  49. *
  50. * @param fsize overall file size
  51. * @param off offset of the block in the file
  52. * @param depth depth of the block in the tree, 0 for DBLOCK
  53. * @return off for DBLOCKS (depth == treedepth),
  54. * otherwise an offset past the end
  55. * of the file that does not overlap
  56. * with the range for any other block
  57. */
  58. static uint64_t
  59. compute_disk_offset (uint64_t fsize, uint64_t off, unsigned int depth)
  60. {
  61. unsigned int i;
  62. uint64_t lsize; /* what is the size of all IBlocks for depth "i"? */
  63. uint64_t loff; /* where do IBlocks for depth "i" start? */
  64. unsigned int ioff; /* which IBlock corresponds to "off" at depth "i"? */
  65. if (0 == depth)
  66. return off;
  67. /* first IBlocks start at the end of file, rounded up
  68. * to full DBLOCK_SIZE */
  69. loff = ((fsize + DBLOCK_SIZE - 1) / DBLOCK_SIZE) * DBLOCK_SIZE;
  70. lsize =
  71. ((fsize + DBLOCK_SIZE - 1) / DBLOCK_SIZE) * sizeof(struct ContentHashKey);
  72. GNUNET_assert (0 == (off % DBLOCK_SIZE));
  73. ioff = (off / DBLOCK_SIZE);
  74. for (i = 1; i < depth; i++)
  75. {
  76. loff += lsize;
  77. lsize = (lsize + CHK_PER_INODE - 1) / CHK_PER_INODE;
  78. GNUNET_assert (lsize > 0);
  79. GNUNET_assert (0 == (ioff % CHK_PER_INODE));
  80. ioff /= CHK_PER_INODE;
  81. }
  82. return loff + ioff * sizeof(struct ContentHashKey);
  83. }
  84. /**
  85. * Fill in all of the generic fields for a download event and call the
  86. * callback.
  87. *
  88. * @param pi structure to fill in
  89. * @param dc overall download context
  90. */
  91. void
  92. GNUNET_FS_download_make_status_ (struct GNUNET_FS_ProgressInfo *pi,
  93. struct GNUNET_FS_DownloadContext *dc)
  94. {
  95. pi->value.download.dc = dc;
  96. pi->value.download.cctx = dc->client_info;
  97. pi->value.download.pctx =
  98. (NULL == dc->parent) ? NULL : dc->parent->client_info;
  99. pi->value.download.sctx =
  100. (NULL == dc->search) ? NULL : dc->search->client_info;
  101. pi->value.download.uri = dc->uri;
  102. pi->value.download.filename = dc->filename;
  103. pi->value.download.size = dc->length;
  104. /* FIXME: Fix duration calculation to account for pauses */
  105. pi->value.download.duration =
  106. GNUNET_TIME_absolute_get_duration (dc->start_time);
  107. pi->value.download.completed = dc->completed;
  108. pi->value.download.anonymity = dc->anonymity;
  109. pi->value.download.eta =
  110. GNUNET_TIME_calculate_eta (dc->start_time, dc->completed, dc->length);
  111. pi->value.download.is_active = (NULL == dc->mq) ? GNUNET_NO : GNUNET_YES;
  112. pi->fsh = dc->h;
  113. if (0 == (dc->options & GNUNET_FS_DOWNLOAD_IS_PROBE))
  114. dc->client_info = dc->h->upcb (dc->h->upcb_cls, pi);
  115. else
  116. dc->client_info = GNUNET_FS_search_probe_progress_ (NULL, pi);
  117. }
  118. /**
  119. * Closure for iterator processing results.
  120. */
  121. struct ProcessResultClosure
  122. {
  123. /**
  124. * Hash of data.
  125. */
  126. struct GNUNET_HashCode query;
  127. /**
  128. * Data found in P2P network.
  129. */
  130. const void *data;
  131. /**
  132. * Our download context.
  133. */
  134. struct GNUNET_FS_DownloadContext *dc;
  135. /**
  136. * When did we last transmit the request?
  137. */
  138. struct GNUNET_TIME_Absolute last_transmission;
  139. /**
  140. * Number of bytes in data.
  141. */
  142. size_t size;
  143. /**
  144. * Type of data.
  145. */
  146. enum GNUNET_BLOCK_Type type;
  147. /**
  148. * Flag to indicate if this block should be stored on disk.
  149. */
  150. int do_store;
  151. /**
  152. * how much respect did we offer to get this reply?
  153. */
  154. uint32_t respect_offered;
  155. /**
  156. * how often did we transmit the query?
  157. */
  158. uint32_t num_transmissions;
  159. };
  160. /**
  161. * Iterator over entries in the pending requests in the 'active' map for the
  162. * reply that we just got.
  163. *
  164. * @param cls closure (our 'struct ProcessResultClosure')
  165. * @param key query for the given value / request
  166. * @param value value in the hash map (a 'struct DownloadRequest')
  167. * @return #GNUNET_YES (we should continue to iterate); unless serious error
  168. */
  169. static int
  170. process_result_with_request (void *cls,
  171. const struct GNUNET_HashCode *key,
  172. void *value);
  173. /**
  174. * We've found a matching block without downloading it.
  175. * Encrypt it and pass it to our "receive" function as
  176. * if we had received it from the network.
  177. *
  178. * @param dc download in question
  179. * @param chk request this relates to
  180. * @param dr request details
  181. * @param block plaintext data matching request
  182. * @param len number of bytes in block
  183. * @param do_store should we still store the block on disk?
  184. * @return GNUNET_OK on success
  185. */
  186. static int
  187. encrypt_existing_match (struct GNUNET_FS_DownloadContext *dc,
  188. const struct ContentHashKey *chk,
  189. struct DownloadRequest *dr,
  190. const char *block,
  191. size_t len,
  192. int do_store)
  193. {
  194. struct ProcessResultClosure prc;
  195. char enc[len];
  196. struct GNUNET_CRYPTO_SymmetricSessionKey sk;
  197. struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
  198. struct GNUNET_HashCode query;
  199. GNUNET_CRYPTO_hash_to_aes_key (&chk->key, &sk, &iv);
  200. if (-1 == GNUNET_CRYPTO_symmetric_encrypt (block, len, &sk, &iv, enc))
  201. {
  202. GNUNET_break (0);
  203. return GNUNET_SYSERR;
  204. }
  205. GNUNET_CRYPTO_hash (enc, len, &query);
  206. if (0 != memcmp (&query, &chk->query, sizeof(struct GNUNET_HashCode)))
  207. {
  208. GNUNET_break_op (0);
  209. return GNUNET_SYSERR;
  210. }
  211. GNUNET_log (
  212. GNUNET_ERROR_TYPE_DEBUG,
  213. "Matching %u byte block for `%s' at offset %llu already present, no need for download!\n",
  214. (unsigned int) len,
  215. dc->filename,
  216. (unsigned long long) dr->offset);
  217. /* already got it! */
  218. prc.dc = dc;
  219. prc.data = enc;
  220. prc.size = len;
  221. prc.type = (0 == dr->depth) ? GNUNET_BLOCK_TYPE_FS_DBLOCK
  222. : GNUNET_BLOCK_TYPE_FS_IBLOCK;
  223. prc.query = chk->query;
  224. prc.do_store = do_store;
  225. prc.last_transmission = GNUNET_TIME_UNIT_FOREVER_ABS;
  226. process_result_with_request (&prc, &chk->key, dr);
  227. return GNUNET_OK;
  228. }
  229. /**
  230. * We've lost our connection with the FS service.
  231. * Re-establish it and re-transmit all of our
  232. * pending requests.
  233. *
  234. * @param dc download context that is having trouble
  235. */
  236. static void
  237. try_reconnect (struct GNUNET_FS_DownloadContext *dc);
  238. /**
  239. * We found an entry in a directory. Check if the respective child
  240. * already exists and if not create the respective child download.
  241. *
  242. * @param cls the parent download
  243. * @param filename name of the file in the directory
  244. * @param uri URI of the file (CHK or LOC)
  245. * @param meta meta data of the file
  246. * @param length number of bytes in data
  247. * @param data contents of the file (or NULL if they were not inlined)
  248. */
  249. static void
  250. trigger_recursive_download (void *cls,
  251. const char *filename,
  252. const struct GNUNET_FS_Uri *uri,
  253. const struct GNUNET_CONTAINER_MetaData *meta,
  254. size_t length,
  255. const void *data);
  256. /**
  257. * We're done downloading a directory. Open the file and
  258. * trigger all of the (remaining) child downloads.
  259. *
  260. * @param dc context of download that just completed
  261. */
  262. static void
  263. full_recursive_download (struct GNUNET_FS_DownloadContext *dc)
  264. {
  265. size_t size;
  266. uint64_t size64;
  267. void *data;
  268. struct GNUNET_DISK_FileHandle *h;
  269. struct GNUNET_DISK_MapHandle *m;
  270. size64 = GNUNET_FS_uri_chk_get_file_size (dc->uri);
  271. size = (size_t) size64;
  272. if (size64 != (uint64_t) size)
  273. {
  274. GNUNET_log (
  275. GNUNET_ERROR_TYPE_ERROR,
  276. _ (
  277. "Recursive downloads of directories larger than 4 GB are not supported on 32-bit systems\n"));
  278. return;
  279. }
  280. if (NULL != dc->filename)
  281. {
  282. h = GNUNET_DISK_file_open (dc->filename,
  283. GNUNET_DISK_OPEN_READ,
  284. GNUNET_DISK_PERM_NONE);
  285. }
  286. else
  287. {
  288. GNUNET_assert (NULL != dc->temp_filename);
  289. h = GNUNET_DISK_file_open (dc->temp_filename,
  290. GNUNET_DISK_OPEN_READ,
  291. GNUNET_DISK_PERM_NONE);
  292. }
  293. if (NULL == h)
  294. return; /* oops */
  295. data = GNUNET_DISK_file_map (h, &m, GNUNET_DISK_MAP_TYPE_READ, size);
  296. if (NULL == data)
  297. {
  298. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  299. _ ("Directory too large for system address space\n"));
  300. }
  301. else
  302. {
  303. if (GNUNET_OK !=
  304. GNUNET_FS_directory_list_contents (size,
  305. data,
  306. 0,
  307. &trigger_recursive_download,
  308. dc))
  309. {
  310. GNUNET_log (
  311. GNUNET_ERROR_TYPE_WARNING,
  312. _ (
  313. "Failed to access full directroy contents of `%s' for recursive download\n"),
  314. dc->filename);
  315. }
  316. GNUNET_DISK_file_unmap (m);
  317. }
  318. GNUNET_DISK_file_close (h);
  319. if (NULL == dc->filename)
  320. {
  321. if (0 != unlink (dc->temp_filename))
  322. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
  323. "unlink",
  324. dc->temp_filename);
  325. GNUNET_free (dc->temp_filename);
  326. dc->temp_filename = NULL;
  327. }
  328. }
  329. /**
  330. * Check if all child-downloads have completed (or trigger them if
  331. * necessary) and once we're completely done, signal completion (and
  332. * possibly recurse to parent). This function MUST be called when the
  333. * download of a file itself is done or when the download of a file is
  334. * done and then later a direct child download has completed (and
  335. * hence this download may complete itself).
  336. *
  337. * @param dc download to check for completion of children
  338. */
  339. static void
  340. check_completed (struct GNUNET_FS_DownloadContext *dc)
  341. {
  342. struct GNUNET_FS_ProgressInfo pi;
  343. struct GNUNET_FS_DownloadContext *pos;
  344. /* first, check if we need to download children */
  345. if (is_recursive_download (dc))
  346. full_recursive_download (dc);
  347. /* then, check if children are done already */
  348. for (pos = dc->child_head; NULL != pos; pos = pos->next)
  349. {
  350. if ((NULL == pos->emsg) && (pos->completed < pos->length))
  351. return; /* not done yet */
  352. if ((NULL != pos->child_head) && (pos->has_finished != GNUNET_YES))
  353. return; /* not transitively done yet */
  354. }
  355. /* All of our children are done, so mark this download done */
  356. dc->has_finished = GNUNET_YES;
  357. if (NULL != dc->job_queue)
  358. {
  359. GNUNET_FS_dequeue_ (dc->job_queue);
  360. dc->job_queue = NULL;
  361. }
  362. if (NULL != dc->task)
  363. {
  364. GNUNET_SCHEDULER_cancel (dc->task);
  365. dc->task = NULL;
  366. }
  367. if (NULL != dc->rfh)
  368. {
  369. GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (dc->rfh));
  370. dc->rfh = NULL;
  371. }
  372. GNUNET_FS_download_sync_ (dc);
  373. /* signal completion */
  374. pi.status = GNUNET_FS_STATUS_DOWNLOAD_COMPLETED;
  375. GNUNET_FS_download_make_status_ (&pi, dc);
  376. /* let parent know */
  377. if (NULL != dc->parent)
  378. check_completed (dc->parent);
  379. }
  380. /**
  381. * We got a block of plaintext data (from the meta data).
  382. * Try it for upward reconstruction of the data. On success,
  383. * the top-level block will move to state BRS_DOWNLOAD_UP.
  384. *
  385. * @param dc context for the download
  386. * @param dr download request to match against
  387. * @param data plaintext data, starting from the beginning of the file
  388. * @param data_len number of bytes in data
  389. */
  390. static void
  391. try_match_block (struct GNUNET_FS_DownloadContext *dc,
  392. struct DownloadRequest *dr,
  393. const char *data,
  394. size_t data_len)
  395. {
  396. struct GNUNET_FS_ProgressInfo pi;
  397. unsigned int i;
  398. char enc[DBLOCK_SIZE];
  399. struct ContentHashKey chks[CHK_PER_INODE];
  400. struct ContentHashKey in_chk;
  401. struct GNUNET_CRYPTO_SymmetricSessionKey sk;
  402. struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
  403. size_t dlen;
  404. struct DownloadRequest *drc;
  405. struct GNUNET_DISK_FileHandle *fh;
  406. int complete;
  407. const char *fn;
  408. const char *odata;
  409. size_t odata_len;
  410. odata = data;
  411. odata_len = data_len;
  412. if (BRS_DOWNLOAD_UP == dr->state)
  413. return;
  414. if (dr->depth > 0)
  415. {
  416. if ((dc->offset > 0) ||
  417. (dc->length < GNUNET_ntohll (dc->uri->data.chk.file_length)))
  418. {
  419. /* NOTE: this test is not tight, but should suffice; the issue
  420. here is that 'dr->num_children' may inherently only specify a
  421. smaller range than what is in the original file;
  422. thus, reconstruction of (some) inner blocks will fail.
  423. FIXME: we might eventually want to write a tighter test to
  424. maximize the circumstances under which we do succeed with
  425. IBlock reconstruction. (need good tests though). */return;
  426. }
  427. complete = GNUNET_YES;
  428. for (i = 0; i < dr->num_children; i++)
  429. {
  430. drc = dr->children[i];
  431. try_match_block (dc, drc, data, data_len);
  432. if (drc->state != BRS_RECONSTRUCT_META_UP)
  433. complete = GNUNET_NO;
  434. else
  435. chks[i] = drc->chk;
  436. }
  437. if (GNUNET_YES != complete)
  438. return;
  439. data = (const char *) chks;
  440. dlen = dr->num_children * sizeof(struct ContentHashKey);
  441. }
  442. else
  443. {
  444. if (dr->offset > data_len)
  445. return; /* oops */
  446. dlen = GNUNET_MIN (data_len - dr->offset, DBLOCK_SIZE);
  447. }
  448. GNUNET_CRYPTO_hash (&data[dr->offset], dlen, &in_chk.key);
  449. GNUNET_CRYPTO_hash_to_aes_key (&in_chk.key, &sk, &iv);
  450. if (-1 ==
  451. GNUNET_CRYPTO_symmetric_encrypt (&data[dr->offset], dlen, &sk, &iv, enc))
  452. {
  453. GNUNET_break (0);
  454. return;
  455. }
  456. GNUNET_CRYPTO_hash (enc, dlen, &in_chk.query);
  457. switch (dr->state)
  458. {
  459. case BRS_INIT:
  460. dr->chk = in_chk;
  461. dr->state = BRS_RECONSTRUCT_META_UP;
  462. break;
  463. case BRS_CHK_SET:
  464. if (0 != memcmp (&in_chk, &dr->chk, sizeof(struct ContentHashKey)))
  465. {
  466. /* other peer provided bogus meta data */
  467. GNUNET_break_op (0);
  468. break;
  469. }
  470. /* write block to disk */
  471. fn = (NULL != dc->filename) ? dc->filename : dc->temp_filename;
  472. if (NULL != fn)
  473. {
  474. fh = GNUNET_DISK_file_open (fn,
  475. GNUNET_DISK_OPEN_READWRITE
  476. | GNUNET_DISK_OPEN_CREATE
  477. | GNUNET_DISK_OPEN_TRUNCATE,
  478. GNUNET_DISK_PERM_USER_READ
  479. | GNUNET_DISK_PERM_USER_WRITE
  480. | GNUNET_DISK_PERM_GROUP_READ
  481. | GNUNET_DISK_PERM_OTHER_READ);
  482. if (NULL == fh)
  483. {
  484. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", fn);
  485. GNUNET_asprintf (&dc->emsg,
  486. _ ("Failed to open file `%s' for writing"),
  487. fn);
  488. GNUNET_DISK_file_close (fh);
  489. dr->state = BRS_ERROR;
  490. pi.status = GNUNET_FS_STATUS_DOWNLOAD_ERROR;
  491. pi.value.download.specifics.error.message = dc->emsg;
  492. GNUNET_FS_download_make_status_ (&pi, dc);
  493. return;
  494. }
  495. if (data_len != GNUNET_DISK_file_write (fh, odata, odata_len))
  496. {
  497. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "write", fn);
  498. GNUNET_asprintf (&dc->emsg,
  499. _ ("Failed to open file `%s' for writing"),
  500. fn);
  501. GNUNET_DISK_file_close (fh);
  502. dr->state = BRS_ERROR;
  503. pi.status = GNUNET_FS_STATUS_DOWNLOAD_ERROR;
  504. pi.value.download.specifics.error.message = dc->emsg;
  505. GNUNET_FS_download_make_status_ (&pi, dc);
  506. return;
  507. }
  508. GNUNET_DISK_file_close (fh);
  509. }
  510. /* signal success */
  511. dr->state = BRS_DOWNLOAD_UP;
  512. dc->completed = dc->length;
  513. GNUNET_FS_download_sync_ (dc);
  514. pi.status = GNUNET_FS_STATUS_DOWNLOAD_PROGRESS;
  515. pi.value.download.specifics.progress.data = data;
  516. pi.value.download.specifics.progress.offset = 0;
  517. pi.value.download.specifics.progress.data_len = dlen;
  518. pi.value.download.specifics.progress.depth = 0;
  519. pi.value.download.specifics.progress.respect_offered = 0;
  520. pi.value.download.specifics.progress.block_download_duration =
  521. GNUNET_TIME_UNIT_ZERO;
  522. GNUNET_FS_download_make_status_ (&pi, dc);
  523. if ((NULL != dc->filename) &&
  524. (0 != truncate (dc->filename,
  525. GNUNET_ntohll (dc->uri->data.chk.file_length))))
  526. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
  527. "truncate",
  528. dc->filename);
  529. check_completed (dc);
  530. break;
  531. default:
  532. /* how did we get here? */
  533. GNUNET_break (0);
  534. break;
  535. }
  536. }
  537. /**
  538. * Type of a function that libextractor calls for each
  539. * meta data item found. If we find full data meta data,
  540. * call 'try_match_block' on it.
  541. *
  542. * @param cls our 'struct GNUNET_FS_DownloadContext*'
  543. * @param plugin_name name of the plugin that produced this value;
  544. * special values can be used (i.e. '&lt;zlib&gt;' for zlib being
  545. * used in the main libextractor library and yielding
  546. * meta data).
  547. * @param type libextractor-type describing the meta data
  548. * @param format basic format information about data
  549. * @param data_mime_type mime-type of data (not of the original file);
  550. * can be NULL (if mime-type is not known)
  551. * @param data actual meta-data found
  552. * @param data_len number of bytes in data
  553. * @return 0 to continue extracting, 1 to abort
  554. */
  555. static int
  556. match_full_data (void *cls,
  557. const char *plugin_name,
  558. enum EXTRACTOR_MetaType type,
  559. enum EXTRACTOR_MetaFormat format,
  560. const char *data_mime_type,
  561. const char *data,
  562. size_t data_len)
  563. {
  564. struct GNUNET_FS_DownloadContext *dc = cls;
  565. if (EXTRACTOR_METATYPE_GNUNET_FULL_DATA != type)
  566. return 0;
  567. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  568. "Found %u bytes of FD!\n",
  569. (unsigned int) data_len);
  570. if (GNUNET_FS_uri_chk_get_file_size (dc->uri) != data_len)
  571. {
  572. GNUNET_break_op (0);
  573. return 1; /* bogus meta data */
  574. }
  575. try_match_block (dc, dc->top_request, data, data_len);
  576. return 1;
  577. }
  578. /**
  579. * Set the state of the given download request to
  580. * BRS_DOWNLOAD_UP and propagate it up the tree.
  581. *
  582. * @param dr download request that is done
  583. */
  584. static void
  585. propagate_up (struct DownloadRequest *dr)
  586. {
  587. unsigned int i;
  588. do
  589. {
  590. dr->state = BRS_DOWNLOAD_UP;
  591. dr = dr->parent;
  592. if (NULL == dr)
  593. break;
  594. for (i = 0; i < dr->num_children; i++)
  595. if (dr->children[i]->state != BRS_DOWNLOAD_UP)
  596. break;
  597. }
  598. while (i == dr->num_children);
  599. }
  600. /**
  601. * Try top-down reconstruction. Before, the given request node
  602. * must have the state BRS_CHK_SET. Afterwards, more nodes may
  603. * have that state or advanced to BRS_DOWNLOAD_DOWN or even
  604. * BRS_DOWNLOAD_UP. It is also possible to get BRS_ERROR on the
  605. * top level.
  606. *
  607. * @param dc overall download this block belongs to
  608. * @param dr block to reconstruct
  609. */
  610. static void
  611. try_top_down_reconstruction (struct GNUNET_FS_DownloadContext *dc,
  612. struct DownloadRequest *dr)
  613. {
  614. uint64_t off;
  615. char block[DBLOCK_SIZE];
  616. struct GNUNET_HashCode key;
  617. uint64_t total;
  618. size_t len;
  619. unsigned int i;
  620. struct DownloadRequest *drc;
  621. uint64_t child_block_size;
  622. const struct ContentHashKey *chks;
  623. int up_done;
  624. GNUNET_assert (NULL != dc->rfh);
  625. GNUNET_assert (BRS_CHK_SET == dr->state);
  626. total = GNUNET_FS_uri_chk_get_file_size (dc->uri);
  627. GNUNET_assert (dr->depth < dc->treedepth);
  628. len = GNUNET_FS_tree_calculate_block_size (total, dr->offset, dr->depth);
  629. GNUNET_assert (len <= DBLOCK_SIZE);
  630. off = compute_disk_offset (total, dr->offset, dr->depth);
  631. if (dc->old_file_size < off + len)
  632. return; /* failure */
  633. if (off != GNUNET_DISK_file_seek (dc->rfh, off, GNUNET_DISK_SEEK_SET))
  634. {
  635. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "seek", dc->filename);
  636. return; /* failure */
  637. }
  638. if (len != GNUNET_DISK_file_read (dc->rfh, block, len))
  639. {
  640. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "read", dc->filename);
  641. return; /* failure */
  642. }
  643. GNUNET_CRYPTO_hash (block, len, &key);
  644. if (0 != memcmp (&key, &dr->chk.key, sizeof(struct GNUNET_HashCode)))
  645. return; /* mismatch */
  646. if (GNUNET_OK !=
  647. encrypt_existing_match (dc, &dr->chk, dr, block, len, GNUNET_NO))
  648. {
  649. /* hash matches but encrypted block does not, really bad */
  650. dr->state = BRS_ERROR;
  651. /* propagate up */
  652. while (NULL != dr->parent)
  653. {
  654. dr = dr->parent;
  655. dr->state = BRS_ERROR;
  656. }
  657. return;
  658. }
  659. /* block matches */
  660. dr->state = BRS_DOWNLOAD_DOWN;
  661. /* set CHKs for children */
  662. up_done = GNUNET_YES;
  663. chks = (const struct ContentHashKey *) block;
  664. for (i = 0; i < dr->num_children; i++)
  665. {
  666. drc = dr->children[i];
  667. GNUNET_assert (drc->offset >= dr->offset);
  668. child_block_size = GNUNET_FS_tree_compute_tree_size (drc->depth);
  669. GNUNET_assert (0 == (drc->offset - dr->offset) % child_block_size);
  670. if (BRS_INIT == drc->state)
  671. {
  672. drc->state = BRS_CHK_SET;
  673. drc->chk = chks[drc->chk_idx];
  674. try_top_down_reconstruction (dc, drc);
  675. }
  676. if (BRS_DOWNLOAD_UP != drc->state)
  677. up_done = GNUNET_NO; /* children not all done */
  678. }
  679. if (GNUNET_YES == up_done)
  680. propagate_up (dr); /* children all done (or no children...) */
  681. }
  682. /**
  683. * Add entries to the message queue.
  684. *
  685. * @param cls our download context
  686. * @param key unused
  687. * @param entry entry of type `struct DownloadRequest`
  688. * @return #GNUNET_OK
  689. */
  690. static int
  691. retry_entry (void *cls, const struct GNUNET_HashCode *key, void *entry)
  692. {
  693. struct GNUNET_FS_DownloadContext *dc = cls;
  694. struct DownloadRequest *dr = entry;
  695. struct SearchMessage *sm;
  696. struct GNUNET_MQ_Envelope *env;
  697. env = GNUNET_MQ_msg (sm, GNUNET_MESSAGE_TYPE_FS_START_SEARCH);
  698. if (0 != (dc->options & GNUNET_FS_DOWNLOAD_OPTION_LOOPBACK_ONLY))
  699. sm->options = htonl (GNUNET_FS_SEARCH_OPTION_LOOPBACK_ONLY);
  700. else
  701. sm->options = htonl (GNUNET_FS_SEARCH_OPTION_NONE);
  702. if (0 == dr->depth)
  703. sm->type = htonl (GNUNET_BLOCK_TYPE_FS_DBLOCK);
  704. else
  705. sm->type = htonl (GNUNET_BLOCK_TYPE_FS_IBLOCK);
  706. sm->anonymity_level = htonl (dc->anonymity);
  707. sm->target = dc->target;
  708. sm->query = dr->chk.query;
  709. GNUNET_MQ_send (dc->mq, env);
  710. return GNUNET_OK;
  711. }
  712. /**
  713. * Schedule the download of the specified block in the tree.
  714. *
  715. * @param dc overall download this block belongs to
  716. * @param dr request to schedule
  717. */
  718. static void
  719. schedule_block_download (struct GNUNET_FS_DownloadContext *dc,
  720. struct DownloadRequest *dr)
  721. {
  722. unsigned int i;
  723. switch (dr->state)
  724. {
  725. case BRS_INIT:
  726. GNUNET_assert (0);
  727. break;
  728. case BRS_RECONSTRUCT_DOWN:
  729. GNUNET_assert (0);
  730. break;
  731. case BRS_RECONSTRUCT_META_UP:
  732. GNUNET_assert (0);
  733. break;
  734. case BRS_RECONSTRUCT_UP:
  735. GNUNET_assert (0);
  736. break;
  737. case BRS_CHK_SET:
  738. /* normal case, start download */
  739. break;
  740. case BRS_DOWNLOAD_DOWN:
  741. for (i = 0; i < dr->num_children; i++)
  742. schedule_block_download (dc, dr->children[i]);
  743. return;
  744. case BRS_DOWNLOAD_UP:
  745. /* We're done! */
  746. return;
  747. case BRS_ERROR:
  748. GNUNET_break (0);
  749. return;
  750. }
  751. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  752. "Scheduling download at offset %llu and depth %u for `%s'\n",
  753. (unsigned long long) dr->offset,
  754. dr->depth,
  755. GNUNET_h2s (&dr->chk.query));
  756. if (GNUNET_NO != GNUNET_CONTAINER_multihashmap_contains_value (dc->active,
  757. &dr->chk.query,
  758. dr))
  759. return; /* already active */
  760. GNUNET_CONTAINER_multihashmap_put (dc->active,
  761. &dr->chk.query,
  762. dr,
  763. GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
  764. if (NULL == dc->mq)
  765. return; /* download not active */
  766. retry_entry (dc, &dr->chk.query, dr);
  767. }
  768. #define GNUNET_FS_URI_CHK_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_CHK_INFIX
  769. /**
  770. * We found an entry in a directory. Check if the respective child
  771. * already exists and if not create the respective child download.
  772. *
  773. * @param cls the parent download
  774. * @param filename name of the file in the directory
  775. * @param uri URI of the file (CHK or LOC)
  776. * @param meta meta data of the file
  777. * @param length number of bytes in data
  778. * @param data contents of the file (or NULL if they were not inlined)
  779. */
  780. static void
  781. trigger_recursive_download (void *cls,
  782. const char *filename,
  783. const struct GNUNET_FS_Uri *uri,
  784. const struct GNUNET_CONTAINER_MetaData *meta,
  785. size_t length,
  786. const void *data)
  787. {
  788. struct GNUNET_FS_DownloadContext *dc = cls;
  789. struct GNUNET_FS_DownloadContext *cpos;
  790. char *temp_name;
  791. char *fn;
  792. char *us;
  793. char *ext;
  794. char *dn;
  795. char *pos;
  796. char *full_name;
  797. char *sfn;
  798. if (NULL == uri)
  799. return; /* entry for the directory itself */
  800. cpos = dc->child_head;
  801. while (NULL != cpos)
  802. {
  803. if ((GNUNET_FS_uri_test_equal (uri, cpos->uri)) ||
  804. ((NULL != filename) && (0 == strcmp (cpos->filename, filename))))
  805. break;
  806. cpos = cpos->next;
  807. }
  808. if (NULL != cpos)
  809. return; /* already exists */
  810. fn = NULL;
  811. if (NULL == filename)
  812. {
  813. fn = GNUNET_FS_meta_data_suggest_filename (meta);
  814. if (NULL == fn)
  815. {
  816. us = GNUNET_FS_uri_to_string (uri);
  817. fn = GNUNET_strdup (&us[strlen (GNUNET_FS_URI_CHK_PREFIX)]);
  818. GNUNET_free (us);
  819. }
  820. else if ('.' == fn[0])
  821. {
  822. ext = fn;
  823. us = GNUNET_FS_uri_to_string (uri);
  824. GNUNET_asprintf (&fn,
  825. "%s%s",
  826. &us[strlen (GNUNET_FS_URI_CHK_PREFIX)],
  827. ext);
  828. GNUNET_free (ext);
  829. GNUNET_free (us);
  830. }
  831. /* change '\' to '/' (this should have happened
  832. * during insertion, but malicious peers may
  833. * not have done this) */
  834. while (NULL != (pos = strstr (fn, "\\")))
  835. *pos = '/';
  836. /* remove '../' everywhere (again, well-behaved
  837. * peers don't do this, but don't trust that
  838. * we did not get something nasty) */
  839. while (NULL != (pos = strstr (fn, "../")))
  840. {
  841. pos[0] = '_';
  842. pos[1] = '_';
  843. pos[2] = '_';
  844. }
  845. filename = fn;
  846. }
  847. if (NULL == dc->filename)
  848. {
  849. full_name = NULL;
  850. }
  851. else
  852. {
  853. dn = GNUNET_strdup (dc->filename);
  854. GNUNET_break (
  855. (strlen (dn) >= strlen (GNUNET_FS_DIRECTORY_EXT)) &&
  856. (NULL != strstr (dn + strlen (dn) - strlen (GNUNET_FS_DIRECTORY_EXT),
  857. GNUNET_FS_DIRECTORY_EXT)));
  858. sfn = GNUNET_strdup (filename);
  859. while ((strlen (sfn) > 0) && ('/' == filename[strlen (sfn) - 1]))
  860. sfn[strlen (sfn) - 1] = '\0';
  861. if ((strlen (dn) >= strlen (GNUNET_FS_DIRECTORY_EXT)) &&
  862. (NULL != strstr (dn + strlen (dn) - strlen (GNUNET_FS_DIRECTORY_EXT),
  863. GNUNET_FS_DIRECTORY_EXT)))
  864. dn[strlen (dn) - strlen (GNUNET_FS_DIRECTORY_EXT)] = '\0';
  865. if ((GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (meta)) &&
  866. ((strlen (filename) < strlen (GNUNET_FS_DIRECTORY_EXT)) ||
  867. (NULL == strstr (filename + strlen (filename)
  868. - strlen (GNUNET_FS_DIRECTORY_EXT),
  869. GNUNET_FS_DIRECTORY_EXT))))
  870. {
  871. GNUNET_asprintf (&full_name,
  872. "%s%s%s%s",
  873. dn,
  874. DIR_SEPARATOR_STR,
  875. sfn,
  876. GNUNET_FS_DIRECTORY_EXT);
  877. }
  878. else
  879. {
  880. GNUNET_asprintf (&full_name, "%s%s%s", dn, DIR_SEPARATOR_STR, sfn);
  881. }
  882. GNUNET_free (sfn);
  883. GNUNET_free (dn);
  884. }
  885. if ((NULL != full_name) &&
  886. (GNUNET_OK != GNUNET_DISK_directory_create_for_file (full_name)))
  887. {
  888. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  889. _ (
  890. "Failed to create directory for recursive download of `%s'\n"),
  891. full_name);
  892. GNUNET_free (full_name);
  893. GNUNET_free (fn);
  894. return;
  895. }
  896. temp_name = NULL;
  897. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  898. "Triggering recursive download of size %llu with %u bytes MD\n",
  899. (unsigned long long) GNUNET_FS_uri_chk_get_file_size (uri),
  900. (unsigned int) GNUNET_CONTAINER_meta_data_get_serialized_size (
  901. meta));
  902. GNUNET_FS_download_start (dc->h,
  903. uri,
  904. meta,
  905. full_name,
  906. temp_name,
  907. 0,
  908. GNUNET_FS_uri_chk_get_file_size (uri),
  909. dc->anonymity,
  910. dc->options,
  911. NULL,
  912. dc);
  913. GNUNET_free (full_name);
  914. GNUNET_free (temp_name);
  915. GNUNET_free (fn);
  916. }
  917. /**
  918. * (recursively) free download request structure
  919. *
  920. * @param dr request to free
  921. */
  922. void
  923. GNUNET_FS_free_download_request_ (struct DownloadRequest *dr)
  924. {
  925. if (NULL == dr)
  926. return;
  927. for (unsigned int i = 0; i < dr->num_children; i++)
  928. GNUNET_FS_free_download_request_ (dr->children[i]);
  929. GNUNET_free (dr->children);
  930. GNUNET_free (dr);
  931. }
  932. /**
  933. * Iterator over entries in the pending requests in the 'active' map for the
  934. * reply that we just got.
  935. *
  936. * @param cls closure (our `struct ProcessResultClosure`)
  937. * @param key query for the given value / request
  938. * @param value value in the hash map (a `struct DownloadRequest`)
  939. * @return #GNUNET_YES (we should continue to iterate); unless serious error
  940. */
  941. static int
  942. process_result_with_request (void *cls,
  943. const struct GNUNET_HashCode *key,
  944. void *value)
  945. {
  946. struct ProcessResultClosure *prc = cls;
  947. struct DownloadRequest *dr = value;
  948. struct GNUNET_FS_DownloadContext *dc = prc->dc;
  949. struct DownloadRequest *drc;
  950. struct GNUNET_DISK_FileHandle *fh = NULL;
  951. struct GNUNET_CRYPTO_SymmetricSessionKey skey;
  952. struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
  953. char pt[prc->size];
  954. struct GNUNET_FS_ProgressInfo pi;
  955. uint64_t off;
  956. size_t bs;
  957. size_t app;
  958. int i;
  959. struct ContentHashKey *chkarr;
  960. GNUNET_log (
  961. GNUNET_ERROR_TYPE_DEBUG,
  962. "Received %u byte block `%s' matching pending request at depth %u and offset %llu/%llu\n",
  963. (unsigned int) prc->size,
  964. GNUNET_h2s (key),
  965. dr->depth,
  966. (unsigned long long) dr->offset,
  967. (unsigned long long) GNUNET_ntohll (dc->uri->data.chk.file_length));
  968. bs = GNUNET_FS_tree_calculate_block_size (GNUNET_ntohll (
  969. dc->uri->data.chk.file_length),
  970. dr->offset,
  971. dr->depth);
  972. if (prc->size != bs)
  973. {
  974. GNUNET_asprintf (
  975. &dc->emsg,
  976. _ (
  977. "Internal error or bogus download URI (expected %lu bytes at depth %u and offset %llu/%llu, got %lu bytes)"),
  978. bs,
  979. dr->depth,
  980. (unsigned long long) dr->offset,
  981. (unsigned long long) GNUNET_ntohll (dc->uri->data.chk.file_length),
  982. prc->size);
  983. GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s\n", dc->emsg);
  984. while (NULL != dr->parent)
  985. {
  986. dr->state = BRS_ERROR;
  987. dr = dr->parent;
  988. }
  989. dr->state = BRS_ERROR;
  990. goto signal_error;
  991. }
  992. (void) GNUNET_CONTAINER_multihashmap_remove (dc->active, &prc->query, dr);
  993. GNUNET_CRYPTO_hash_to_aes_key (&dr->chk.key, &skey, &iv);
  994. if (-1 ==
  995. GNUNET_CRYPTO_symmetric_decrypt (prc->data, prc->size, &skey, &iv, pt))
  996. {
  997. GNUNET_break (0);
  998. dc->emsg = GNUNET_strdup (_ ("internal error decrypting content"));
  999. goto signal_error;
  1000. }
  1001. off = compute_disk_offset (GNUNET_ntohll (dc->uri->data.chk.file_length),
  1002. dr->offset,
  1003. dr->depth);
  1004. /* save to disk */
  1005. if ((GNUNET_YES == prc->do_store) &&
  1006. ((NULL != dc->filename) || (is_recursive_download (dc))) &&
  1007. ((dr->depth == dc->treedepth) ||
  1008. (0 == (dc->options & GNUNET_FS_DOWNLOAD_NO_TEMPORARIES))))
  1009. {
  1010. fh = GNUNET_DISK_file_open (NULL != dc->filename ? dc->filename
  1011. : dc->temp_filename,
  1012. GNUNET_DISK_OPEN_READWRITE
  1013. | GNUNET_DISK_OPEN_CREATE,
  1014. GNUNET_DISK_PERM_USER_READ
  1015. | GNUNET_DISK_PERM_USER_WRITE
  1016. | GNUNET_DISK_PERM_GROUP_READ
  1017. | GNUNET_DISK_PERM_OTHER_READ);
  1018. if (NULL == fh)
  1019. {
  1020. GNUNET_asprintf (&dc->emsg,
  1021. _ ("Download failed: could not open file `%s': %s"),
  1022. dc->filename,
  1023. strerror (errno));
  1024. goto signal_error;
  1025. }
  1026. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1027. "Saving decrypted block to disk at offset %llu\n",
  1028. (unsigned long long) off);
  1029. if ((off != GNUNET_DISK_file_seek (fh, off, GNUNET_DISK_SEEK_SET)))
  1030. {
  1031. GNUNET_asprintf (&dc->emsg,
  1032. _ ("Failed to seek to offset %llu in file `%s': %s"),
  1033. (unsigned long long) off,
  1034. dc->filename,
  1035. strerror (errno));
  1036. goto signal_error;
  1037. }
  1038. if (prc->size != GNUNET_DISK_file_write (fh, pt, prc->size))
  1039. {
  1040. GNUNET_asprintf (
  1041. &dc->emsg,
  1042. _ ("Failed to write block of %u bytes at offset %llu in file `%s': %s"),
  1043. (unsigned int) prc->size,
  1044. (unsigned long long) off,
  1045. dc->filename,
  1046. strerror (errno));
  1047. goto signal_error;
  1048. }
  1049. GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fh));
  1050. fh = NULL;
  1051. }
  1052. if (0 == dr->depth)
  1053. {
  1054. /* DBLOCK, update progress and try recursion if applicable */
  1055. app = prc->size;
  1056. if (dr->offset < dc->offset)
  1057. {
  1058. /* starting offset begins in the middle of pt,
  1059. * do not count first bytes as progress */
  1060. GNUNET_assert (app > (dc->offset - dr->offset));
  1061. app -= (dc->offset - dr->offset);
  1062. }
  1063. if (dr->offset + prc->size > dc->offset + dc->length)
  1064. {
  1065. /* end of block is after relevant range,
  1066. * do not count last bytes as progress */
  1067. GNUNET_assert (app >
  1068. (dr->offset + prc->size) - (dc->offset + dc->length));
  1069. app -= (dr->offset + prc->size) - (dc->offset + dc->length);
  1070. }
  1071. dc->completed += app;
  1072. /* do recursive download if option is set and either meta data
  1073. * says it is a directory or if no meta data is given AND filename
  1074. * ends in '.gnd' (top-level case) */
  1075. if (is_recursive_download (dc))
  1076. GNUNET_FS_directory_list_contents (prc->size,
  1077. pt,
  1078. off,
  1079. &trigger_recursive_download,
  1080. dc);
  1081. }
  1082. GNUNET_assert (dc->completed <= dc->length);
  1083. dr->state = BRS_DOWNLOAD_DOWN;
  1084. pi.status = GNUNET_FS_STATUS_DOWNLOAD_PROGRESS;
  1085. pi.value.download.specifics.progress.data = pt;
  1086. pi.value.download.specifics.progress.offset = dr->offset;
  1087. pi.value.download.specifics.progress.data_len = prc->size;
  1088. pi.value.download.specifics.progress.depth = dr->depth;
  1089. pi.value.download.specifics.progress.respect_offered = prc->respect_offered;
  1090. pi.value.download.specifics.progress.num_transmissions =
  1091. prc->num_transmissions;
  1092. if (prc->last_transmission.abs_value_us !=
  1093. GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us)
  1094. pi.value.download.specifics.progress.block_download_duration =
  1095. GNUNET_TIME_absolute_get_duration (prc->last_transmission);
  1096. else
  1097. pi.value.download.specifics.progress.block_download_duration =
  1098. GNUNET_TIME_UNIT_ZERO; /* found locally */
  1099. GNUNET_FS_download_make_status_ (&pi, dc);
  1100. if (0 == dr->depth)
  1101. propagate_up (dr);
  1102. if (dc->completed == dc->length)
  1103. {
  1104. /* download completed, signal */
  1105. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1106. "Download completed, truncating file to desired length %llu\n",
  1107. (unsigned long long) GNUNET_ntohll (
  1108. dc->uri->data.chk.file_length));
  1109. /* truncate file to size (since we store IBlocks at the end) */
  1110. if (NULL != dc->filename)
  1111. {
  1112. if (0 != truncate (dc->filename,
  1113. GNUNET_ntohll (dc->uri->data.chk.file_length)))
  1114. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
  1115. "truncate",
  1116. dc->filename);
  1117. }
  1118. GNUNET_assert (0 == dr->depth);
  1119. check_completed (dc);
  1120. }
  1121. if (0 == dr->depth)
  1122. {
  1123. /* bottom of the tree, no child downloads possible, just sync */
  1124. GNUNET_FS_download_sync_ (dc);
  1125. return GNUNET_YES;
  1126. }
  1127. GNUNET_log (
  1128. GNUNET_ERROR_TYPE_DEBUG,
  1129. "Triggering downloads of children (this block was at depth %u and offset %llu)\n",
  1130. dr->depth,
  1131. (unsigned long long) dr->offset);
  1132. GNUNET_assert (0 == (prc->size % sizeof(struct ContentHashKey)));
  1133. chkarr = (struct ContentHashKey *) pt;
  1134. for (i = dr->num_children - 1; i >= 0; i--)
  1135. {
  1136. drc = dr->children[i];
  1137. switch (drc->state)
  1138. {
  1139. case BRS_INIT:
  1140. if ((drc->chk_idx + 1) * sizeof(struct ContentHashKey) > prc->size)
  1141. {
  1142. /* 'chkarr' does not have enough space for this chk_idx;
  1143. internal error! */
  1144. GNUNET_break (0);
  1145. GNUNET_assert (0);
  1146. dc->emsg = GNUNET_strdup (_ ("internal error decoding tree"));
  1147. goto signal_error;
  1148. }
  1149. drc->chk = chkarr[drc->chk_idx];
  1150. drc->state = BRS_CHK_SET;
  1151. if (GNUNET_YES == dc->issue_requests)
  1152. schedule_block_download (dc, drc);
  1153. break;
  1154. case BRS_RECONSTRUCT_DOWN:
  1155. GNUNET_assert (0);
  1156. break;
  1157. case BRS_RECONSTRUCT_META_UP:
  1158. GNUNET_assert (0);
  1159. break;
  1160. case BRS_RECONSTRUCT_UP:
  1161. GNUNET_assert (0);
  1162. break;
  1163. case BRS_CHK_SET:
  1164. GNUNET_assert (0);
  1165. break;
  1166. case BRS_DOWNLOAD_DOWN:
  1167. GNUNET_assert (0);
  1168. break;
  1169. case BRS_DOWNLOAD_UP:
  1170. GNUNET_assert (0);
  1171. break;
  1172. case BRS_ERROR:
  1173. GNUNET_assert (0);
  1174. break;
  1175. default:
  1176. GNUNET_assert (0);
  1177. break;
  1178. }
  1179. }
  1180. GNUNET_FS_download_sync_ (dc);
  1181. return GNUNET_YES;
  1182. signal_error:
  1183. if (NULL != fh)
  1184. GNUNET_DISK_file_close (fh);
  1185. pi.status = GNUNET_FS_STATUS_DOWNLOAD_ERROR;
  1186. pi.value.download.specifics.error.message = dc->emsg;
  1187. GNUNET_FS_download_make_status_ (&pi, dc);
  1188. GNUNET_MQ_destroy (dc->mq);
  1189. dc->mq = NULL;
  1190. GNUNET_FS_free_download_request_ (dc->top_request);
  1191. dc->top_request = NULL;
  1192. if (NULL != dc->job_queue)
  1193. {
  1194. GNUNET_FS_dequeue_ (dc->job_queue);
  1195. dc->job_queue = NULL;
  1196. }
  1197. GNUNET_FS_download_sync_ (dc);
  1198. return GNUNET_NO;
  1199. }
  1200. /**
  1201. * Type of a function to call when we check the PUT message
  1202. * from the service.
  1203. *
  1204. * @param cls closure
  1205. * @param msg message received
  1206. */
  1207. static int
  1208. check_put (void *cls, const struct ClientPutMessage *cm)
  1209. {
  1210. /* any varsize length is OK */
  1211. return GNUNET_OK;
  1212. }
  1213. /**
  1214. * Type of a function to call when we receive a message
  1215. * from the service.
  1216. *
  1217. * @param cls closure
  1218. * @param msg message received
  1219. */
  1220. static void
  1221. handle_put (void *cls, const struct ClientPutMessage *cm)
  1222. {
  1223. struct GNUNET_FS_DownloadContext *dc = cls;
  1224. uint16_t msize = ntohs (cm->header.size) - sizeof(*cm);
  1225. struct ProcessResultClosure prc;
  1226. prc.dc = dc;
  1227. prc.data = &cm[1];
  1228. prc.last_transmission = GNUNET_TIME_absolute_ntoh (cm->last_transmission);
  1229. prc.size = msize;
  1230. prc.type = ntohl (cm->type);
  1231. prc.do_store = GNUNET_YES;
  1232. prc.respect_offered = ntohl (cm->respect_offered);
  1233. prc.num_transmissions = ntohl (cm->num_transmissions);
  1234. GNUNET_CRYPTO_hash (prc.data, msize, &prc.query);
  1235. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1236. "Received result for query `%s' from FS service\n",
  1237. GNUNET_h2s (&prc.query));
  1238. GNUNET_CONTAINER_multihashmap_get_multiple (dc->active,
  1239. &prc.query,
  1240. &process_result_with_request,
  1241. &prc);
  1242. }
  1243. /**
  1244. * Generic error handler, called with the appropriate error code and
  1245. * the same closure specified at the creation of the message queue.
  1246. * Not every message queue implementation supports an error handler.
  1247. *
  1248. * @param cls closure with the `struct GNUNET_FS_DownloadContext *`
  1249. * @param error error code
  1250. */
  1251. static void
  1252. download_mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
  1253. {
  1254. struct GNUNET_FS_DownloadContext *dc = cls;
  1255. if (NULL != dc->mq)
  1256. {
  1257. GNUNET_MQ_destroy (dc->mq);
  1258. dc->mq = NULL;
  1259. }
  1260. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1261. "Transmitting download request failed, trying to reconnect\n");
  1262. try_reconnect (dc);
  1263. }
  1264. /**
  1265. * Reconnect to the FS service and transmit our queries NOW.
  1266. *
  1267. * @param cls our download context
  1268. */
  1269. static void
  1270. do_reconnect (void *cls)
  1271. {
  1272. struct GNUNET_FS_DownloadContext *dc = cls;
  1273. struct GNUNET_MQ_MessageHandler handlers[] =
  1274. { GNUNET_MQ_hd_var_size (put,
  1275. GNUNET_MESSAGE_TYPE_FS_PUT,
  1276. struct ClientPutMessage,
  1277. dc),
  1278. GNUNET_MQ_handler_end () };
  1279. dc->task = NULL;
  1280. dc->mq = GNUNET_CLIENT_connect (dc->h->cfg,
  1281. "fs",
  1282. handlers,
  1283. &download_mq_error_handler,
  1284. dc);
  1285. if (NULL == dc->mq)
  1286. {
  1287. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  1288. "Connecting to `%s'-service failed, will try again.\n",
  1289. "FS");
  1290. try_reconnect (dc);
  1291. return;
  1292. }
  1293. GNUNET_CONTAINER_multihashmap_iterate (dc->active, &retry_entry, dc);
  1294. }
  1295. /**
  1296. * We've lost our connection with the FS service.
  1297. * Re-establish it and re-transmit all of our
  1298. * pending requests.
  1299. *
  1300. * @param dc download context that is having trouble
  1301. */
  1302. static void
  1303. try_reconnect (struct GNUNET_FS_DownloadContext *dc)
  1304. {
  1305. if (NULL != dc->mq)
  1306. {
  1307. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1308. "Moving all requests back to pending list\n");
  1309. GNUNET_MQ_destroy (dc->mq);
  1310. dc->mq = NULL;
  1311. }
  1312. if (0 == dc->reconnect_backoff.rel_value_us)
  1313. dc->reconnect_backoff = GNUNET_TIME_UNIT_MILLISECONDS;
  1314. else
  1315. dc->reconnect_backoff = GNUNET_TIME_STD_BACKOFF (dc->reconnect_backoff);
  1316. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1317. "Will try to reconnect in %s\n",
  1318. GNUNET_STRINGS_relative_time_to_string (dc->reconnect_backoff,
  1319. GNUNET_YES));
  1320. GNUNET_break (NULL != dc->job_queue);
  1321. dc->task =
  1322. GNUNET_SCHEDULER_add_delayed (dc->reconnect_backoff, &do_reconnect, dc);
  1323. }
  1324. /**
  1325. * We're allowed to ask the FS service for our blocks. Start the download.
  1326. *
  1327. * @param cls the 'struct GNUNET_FS_DownloadContext'
  1328. * @param mq handle to use for communcation with FS (we must destroy it!)
  1329. */
  1330. static void
  1331. activate_fs_download (void *cls)
  1332. {
  1333. struct GNUNET_FS_DownloadContext *dc = cls;
  1334. struct GNUNET_FS_ProgressInfo pi;
  1335. GNUNET_assert (NULL == dc->mq);
  1336. GNUNET_assert (NULL != dc->active);
  1337. do_reconnect (dc);
  1338. if (NULL != dc->mq)
  1339. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download activated\n");
  1340. pi.status = GNUNET_FS_STATUS_DOWNLOAD_ACTIVE;
  1341. GNUNET_FS_download_make_status_ (&pi, dc);
  1342. }
  1343. /**
  1344. * We must stop to ask the FS service for our blocks. Pause the download.
  1345. *
  1346. * @param cls the `struct GNUNET_FS_DownloadContext`
  1347. */
  1348. static void
  1349. deactivate_fs_download (void *cls)
  1350. {
  1351. struct GNUNET_FS_DownloadContext *dc = cls;
  1352. struct GNUNET_FS_ProgressInfo pi;
  1353. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download deactivated\n");
  1354. if (NULL != dc->mq)
  1355. {
  1356. GNUNET_MQ_destroy (dc->mq);
  1357. dc->mq = NULL;
  1358. }
  1359. pi.status = GNUNET_FS_STATUS_DOWNLOAD_INACTIVE;
  1360. GNUNET_FS_download_make_status_ (&pi, dc);
  1361. }
  1362. /**
  1363. * (recursively) Create a download request structure.
  1364. *
  1365. * @param parent parent of the current entry
  1366. * @param chk_idx index of the chk for this block in the parent block
  1367. * @param depth depth of the current entry, 0 are the DBLOCKs,
  1368. * top level block is 'dc->treedepth - 1'
  1369. * @param dr_offset offset in the original file this block maps to
  1370. * (as in, offset of the first byte of the first DBLOCK
  1371. * in the subtree rooted in the returned download request tree)
  1372. * @param file_start_offset desired starting offset for the download
  1373. * in the original file; requesting tree should not contain
  1374. * DBLOCKs prior to the file_start_offset
  1375. * @param desired_length desired number of bytes the user wanted to access
  1376. * (from file_start_offset). Resulting tree should not contain
  1377. * DBLOCKs after file_start_offset + file_length.
  1378. * @return download request tree for the given range of DBLOCKs at
  1379. * the specified depth
  1380. */
  1381. static struct DownloadRequest *
  1382. create_download_request (struct DownloadRequest *parent,
  1383. unsigned int chk_idx,
  1384. unsigned int depth,
  1385. uint64_t dr_offset,
  1386. uint64_t file_start_offset,
  1387. uint64_t desired_length)
  1388. {
  1389. struct DownloadRequest *dr;
  1390. unsigned int i;
  1391. unsigned int head_skip;
  1392. uint64_t child_block_size;
  1393. dr = GNUNET_new (struct DownloadRequest);
  1394. dr->parent = parent;
  1395. dr->depth = depth;
  1396. dr->offset = dr_offset;
  1397. dr->chk_idx = chk_idx;
  1398. if (0 == depth)
  1399. return dr;
  1400. child_block_size = GNUNET_FS_tree_compute_tree_size (depth - 1);
  1401. /* calculate how many blocks at this level are not interesting
  1402. * from the start (rounded down), either because of the requested
  1403. * file offset or because this IBlock is further along */
  1404. if (dr_offset < file_start_offset)
  1405. {
  1406. head_skip = (file_start_offset - dr_offset) / child_block_size;
  1407. }
  1408. else
  1409. {
  1410. head_skip = 0;
  1411. }
  1412. /* calculate index of last block at this level that is interesting (rounded up) */
  1413. dr->num_children =
  1414. (file_start_offset + desired_length - dr_offset) / child_block_size;
  1415. if (dr->num_children * child_block_size <
  1416. file_start_offset + desired_length - dr_offset)
  1417. dr->num_children++; /* round up */
  1418. GNUNET_assert (dr->num_children > head_skip);
  1419. dr->num_children -= head_skip;
  1420. if (dr->num_children > CHK_PER_INODE)
  1421. dr->num_children = CHK_PER_INODE; /* cap at max */
  1422. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1423. "Block at offset %llu and depth %u has %u children\n",
  1424. (unsigned long long) dr_offset,
  1425. depth,
  1426. dr->num_children);
  1427. /* now we can get the total number of *interesting* children for this block */
  1428. /* why else would we have gotten here to begin with? (that'd be a bad logic error) */
  1429. GNUNET_assert (dr->num_children > 0);
  1430. dr->children = GNUNET_new_array (dr->num_children, struct DownloadRequest *);
  1431. for (i = 0; i < dr->num_children; i++)
  1432. {
  1433. dr->children[i] =
  1434. create_download_request (dr,
  1435. i + head_skip,
  1436. depth - 1,
  1437. dr_offset + (i + head_skip) * child_block_size,
  1438. file_start_offset,
  1439. desired_length);
  1440. }
  1441. return dr;
  1442. }
  1443. /**
  1444. * Continuation after a possible attempt to reconstruct
  1445. * the current IBlock from the existing file.
  1446. *
  1447. * @param cls the 'struct ReconstructContext'
  1448. */
  1449. static void
  1450. reconstruct_cont (void *cls)
  1451. {
  1452. struct GNUNET_FS_DownloadContext *dc = cls;
  1453. /* clean up state from tree encoder */
  1454. if (NULL != dc->task)
  1455. {
  1456. GNUNET_SCHEDULER_cancel (dc->task);
  1457. dc->task = NULL;
  1458. }
  1459. if (NULL != dc->rfh)
  1460. {
  1461. GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (dc->rfh));
  1462. dc->rfh = NULL;
  1463. }
  1464. /* start "normal" download */
  1465. dc->issue_requests = GNUNET_YES;
  1466. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting normal download\n");
  1467. schedule_block_download (dc, dc->top_request);
  1468. }
  1469. /**
  1470. * Task requesting the next block from the tree encoder.
  1471. *
  1472. * @param cls the 'struct GNUJNET_FS_DownloadContext' we're processing
  1473. */
  1474. static void
  1475. get_next_block (void *cls)
  1476. {
  1477. struct GNUNET_FS_DownloadContext *dc = cls;
  1478. dc->task = NULL;
  1479. GNUNET_FS_tree_encoder_next (dc->te);
  1480. }
  1481. /**
  1482. * Function called asking for the current (encoded)
  1483. * block to be processed. After processing the
  1484. * client should either call "GNUNET_FS_tree_encode_next"
  1485. * or (on error) "GNUNET_FS_tree_encode_finish".
  1486. *
  1487. * This function checks if the content on disk matches
  1488. * the expected content based on the URI.
  1489. *
  1490. * @param cls closure
  1491. * @param chk content hash key for the block
  1492. * @param offset offset of the block
  1493. * @param depth depth of the block, 0 for DBLOCK
  1494. * @param type type of the block (IBLOCK or DBLOCK)
  1495. * @param block the (encrypted) block
  1496. * @param block_size size of block (in bytes)
  1497. */
  1498. static void
  1499. reconstruct_cb (void *cls,
  1500. const struct ContentHashKey *chk,
  1501. uint64_t offset,
  1502. unsigned int depth,
  1503. enum GNUNET_BLOCK_Type type,
  1504. const void *block,
  1505. uint16_t block_size)
  1506. {
  1507. struct GNUNET_FS_DownloadContext *dc = cls;
  1508. struct GNUNET_FS_ProgressInfo pi;
  1509. struct DownloadRequest *dr;
  1510. uint64_t blen;
  1511. unsigned int chld;
  1512. /* find corresponding request entry */
  1513. dr = dc->top_request;
  1514. while (dr->depth > depth)
  1515. {
  1516. GNUNET_assert (dr->num_children > 0);
  1517. blen = GNUNET_FS_tree_compute_tree_size (dr->depth - 1);
  1518. chld = (offset - dr->offset) / blen;
  1519. if (chld < dr->children[0]->chk_idx)
  1520. {
  1521. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1522. "Block %u < %u irrelevant for our range\n",
  1523. chld,
  1524. dr->children[0]->chk_idx);
  1525. dc->task = GNUNET_SCHEDULER_add_now (&get_next_block, dc);
  1526. return; /* irrelevant block */
  1527. }
  1528. if (chld > dr->children[dr->num_children - 1]->chk_idx)
  1529. {
  1530. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1531. "Block %u > %u irrelevant for our range\n",
  1532. chld,
  1533. dr->children[dr->num_children - 1]->chk_idx);
  1534. dc->task = GNUNET_SCHEDULER_add_now (&get_next_block, dc);
  1535. return; /* irrelevant block */
  1536. }
  1537. dr = dr->children[chld - dr->children[0]->chk_idx];
  1538. }
  1539. GNUNET_log (
  1540. GNUNET_ERROR_TYPE_DEBUG,
  1541. "Matched TE block with request at offset %llu and depth %u in state %d\n",
  1542. (unsigned long long) dr->offset,
  1543. dr->depth,
  1544. dr->state);
  1545. /* FIXME: this code needs more testing and might
  1546. need to handle more states... */
  1547. switch (dr->state)
  1548. {
  1549. case BRS_INIT:
  1550. break;
  1551. case BRS_RECONSTRUCT_DOWN:
  1552. break;
  1553. case BRS_RECONSTRUCT_META_UP:
  1554. break;
  1555. case BRS_RECONSTRUCT_UP:
  1556. break;
  1557. case BRS_CHK_SET:
  1558. if (0 == memcmp (chk, &dr->chk, sizeof(struct ContentHashKey)))
  1559. {
  1560. GNUNET_log (
  1561. GNUNET_ERROR_TYPE_DEBUG,
  1562. "Reconstruction succeeded, can use block at offset %llu, depth %u\n",
  1563. (unsigned long long) offset,
  1564. depth);
  1565. /* block matches, hence tree below matches;
  1566. * this request is done! */
  1567. dr->state = BRS_DOWNLOAD_UP;
  1568. (void) GNUNET_CONTAINER_multihashmap_remove (dc->active,
  1569. &dr->chk.query,
  1570. dr);
  1571. /* calculate how many bytes of payload this block
  1572. * corresponds to */
  1573. blen = GNUNET_FS_tree_compute_tree_size (dr->depth);
  1574. /* how many of those bytes are in the requested range? */
  1575. blen = GNUNET_MIN (blen, dc->length + dc->offset - dr->offset);
  1576. /* signal progress */
  1577. dc->completed += blen;
  1578. pi.status = GNUNET_FS_STATUS_DOWNLOAD_PROGRESS;
  1579. pi.value.download.specifics.progress.data = NULL;
  1580. pi.value.download.specifics.progress.offset = offset;
  1581. pi.value.download.specifics.progress.data_len = 0;
  1582. pi.value.download.specifics.progress.depth = 0;
  1583. pi.value.download.specifics.progress.respect_offered = 0;
  1584. pi.value.download.specifics.progress.block_download_duration =
  1585. GNUNET_TIME_UNIT_ZERO;
  1586. GNUNET_FS_download_make_status_ (&pi, dc);
  1587. /* FIXME: duplicated code from 'process_result_with_request - refactor */
  1588. if (dc->completed == dc->length)
  1589. {
  1590. /* download completed, signal */
  1591. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1592. "Download completed, truncating file to desired length %llu\n",
  1593. (unsigned long long) GNUNET_ntohll (
  1594. dc->uri->data.chk.file_length));
  1595. /* truncate file to size (since we store IBlocks at the end) */
  1596. if (NULL != dc->filename)
  1597. {
  1598. if (0 != truncate (dc->filename,
  1599. GNUNET_ntohll (dc->uri->data.chk.file_length)))
  1600. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
  1601. "truncate",
  1602. dc->filename);
  1603. }
  1604. }
  1605. }
  1606. else
  1607. GNUNET_log (
  1608. GNUNET_ERROR_TYPE_DEBUG,
  1609. "Reconstruction failed, need to download block at offset %llu, depth %u\n",
  1610. (unsigned long long) offset,
  1611. depth);
  1612. break;
  1613. case BRS_DOWNLOAD_DOWN:
  1614. break;
  1615. case BRS_DOWNLOAD_UP:
  1616. break;
  1617. case BRS_ERROR:
  1618. break;
  1619. default:
  1620. GNUNET_assert (0);
  1621. break;
  1622. }
  1623. dc->task = GNUNET_SCHEDULER_add_now (&get_next_block, dc);
  1624. if ((dr == dc->top_request) && (dr->state == BRS_DOWNLOAD_UP))
  1625. check_completed (dc);
  1626. }
  1627. /**
  1628. * Function called by the tree encoder to obtain a block of plaintext
  1629. * data (for the lowest level of the tree).
  1630. *
  1631. * @param cls our 'struct ReconstructContext'
  1632. * @param offset identifies which block to get
  1633. * @param max (maximum) number of bytes to get; returning
  1634. * fewer will also cause errors
  1635. * @param buf where to copy the plaintext buffer
  1636. * @param emsg location to store an error message (on error)
  1637. * @return number of bytes copied to buf, 0 on error
  1638. */
  1639. static size_t
  1640. fh_reader (void *cls, uint64_t offset, size_t max, void *buf, char **emsg)
  1641. {
  1642. struct GNUNET_FS_DownloadContext *dc = cls;
  1643. struct GNUNET_DISK_FileHandle *fh = dc->rfh;
  1644. ssize_t ret;
  1645. if (NULL != emsg)
  1646. *emsg = NULL;
  1647. if (offset != GNUNET_DISK_file_seek (fh, offset, GNUNET_DISK_SEEK_SET))
  1648. {
  1649. if (NULL != emsg)
  1650. *emsg = GNUNET_strdup (strerror (errno));
  1651. return 0;
  1652. }
  1653. ret = GNUNET_DISK_file_read (fh, buf, max);
  1654. if (ret < 0)
  1655. {
  1656. if (NULL != emsg)
  1657. *emsg = GNUNET_strdup (strerror (errno));
  1658. return 0;
  1659. }
  1660. return ret;
  1661. }
  1662. /**
  1663. * Task that creates the initial (top-level) download
  1664. * request for the file.
  1665. *
  1666. * @param cls the 'struct GNUNET_FS_DownloadContext'
  1667. */
  1668. void
  1669. GNUNET_FS_download_start_task_ (void *cls)
  1670. {
  1671. struct GNUNET_FS_DownloadContext *dc = cls;
  1672. struct GNUNET_FS_ProgressInfo pi;
  1673. struct GNUNET_DISK_FileHandle *fh;
  1674. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Start task running...\n");
  1675. dc->task = NULL;
  1676. if (0 == dc->length)
  1677. {
  1678. /* no bytes required! */
  1679. if (NULL != dc->filename)
  1680. {
  1681. fh = GNUNET_DISK_file_open (dc->filename,
  1682. GNUNET_DISK_OPEN_READWRITE
  1683. | GNUNET_DISK_OPEN_CREATE
  1684. | ((0 ==
  1685. GNUNET_FS_uri_chk_get_file_size (dc->uri))
  1686. ? GNUNET_DISK_OPEN_TRUNCATE
  1687. : 0),
  1688. GNUNET_DISK_PERM_USER_READ
  1689. | GNUNET_DISK_PERM_USER_WRITE
  1690. | GNUNET_DISK_PERM_GROUP_READ
  1691. | GNUNET_DISK_PERM_OTHER_READ);
  1692. GNUNET_DISK_file_close (fh);
  1693. }
  1694. GNUNET_FS_download_sync_ (dc);
  1695. pi.status = GNUNET_FS_STATUS_DOWNLOAD_START;
  1696. pi.value.download.specifics.start.meta = dc->meta;
  1697. GNUNET_FS_download_make_status_ (&pi, dc);
  1698. check_completed (dc);
  1699. return;
  1700. }
  1701. if (NULL != dc->emsg)
  1702. return;
  1703. if (NULL == dc->top_request)
  1704. {
  1705. dc->top_request = create_download_request (NULL,
  1706. 0,
  1707. dc->treedepth - 1,
  1708. 0,
  1709. dc->offset,
  1710. dc->length);
  1711. dc->top_request->state = BRS_CHK_SET;
  1712. dc->top_request->chk = (dc->uri->type == GNUNET_FS_URI_CHK)
  1713. ? dc->uri->data.chk.chk
  1714. : dc->uri->data.loc.fi.chk;
  1715. /* signal start */
  1716. GNUNET_FS_download_sync_ (dc);
  1717. if (NULL != dc->search)
  1718. GNUNET_FS_search_result_sync_ (dc->search);
  1719. pi.status = GNUNET_FS_STATUS_DOWNLOAD_START;
  1720. pi.value.download.specifics.start.meta = dc->meta;
  1721. GNUNET_FS_download_make_status_ (&pi, dc);
  1722. }
  1723. GNUNET_FS_download_start_downloading_ (dc);
  1724. /* attempt reconstruction from disk */
  1725. if (GNUNET_YES == GNUNET_DISK_file_test (dc->filename))
  1726. dc->rfh = GNUNET_DISK_file_open (dc->filename,
  1727. GNUNET_DISK_OPEN_READ,
  1728. GNUNET_DISK_PERM_NONE);
  1729. if (dc->top_request->state == BRS_CHK_SET)
  1730. {
  1731. if (NULL != dc->rfh)
  1732. {
  1733. /* first, try top-down */
  1734. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1735. "Trying top-down reconstruction for `%s'\n",
  1736. dc->filename);
  1737. try_top_down_reconstruction (dc, dc->top_request);
  1738. switch (dc->top_request->state)
  1739. {
  1740. case BRS_CHK_SET:
  1741. break; /* normal */
  1742. case BRS_DOWNLOAD_DOWN:
  1743. break; /* normal, some blocks already down */
  1744. case BRS_DOWNLOAD_UP:
  1745. /* already done entirely, party! */
  1746. if (NULL != dc->rfh)
  1747. {
  1748. /* avoid hanging on to file handle longer than
  1749. * necessary */
  1750. GNUNET_DISK_file_close (dc->rfh);
  1751. dc->rfh = NULL;
  1752. }
  1753. return;
  1754. case BRS_ERROR:
  1755. GNUNET_asprintf (&dc->emsg, _ ("Invalid URI"));
  1756. GNUNET_FS_download_sync_ (dc);
  1757. pi.status = GNUNET_FS_STATUS_DOWNLOAD_ERROR;
  1758. pi.value.download.specifics.error.message = dc->emsg;
  1759. GNUNET_FS_download_make_status_ (&pi, dc);
  1760. return;
  1761. default:
  1762. GNUNET_assert (0);
  1763. break;
  1764. }
  1765. }
  1766. }
  1767. /* attempt reconstruction from meta data */
  1768. if ((GNUNET_FS_uri_chk_get_file_size (dc->uri) <= MAX_INLINE_SIZE) &&
  1769. (NULL != dc->meta))
  1770. {
  1771. GNUNET_log (
  1772. GNUNET_ERROR_TYPE_DEBUG,
  1773. "Trying to find embedded meta data for download of size %llu with %u bytes MD\n",
  1774. (unsigned long long) GNUNET_FS_uri_chk_get_file_size (dc->uri),
  1775. (unsigned int) GNUNET_CONTAINER_meta_data_get_serialized_size (dc->meta));
  1776. GNUNET_CONTAINER_meta_data_iterate (dc->meta, &match_full_data, dc);
  1777. if (BRS_DOWNLOAD_UP == dc->top_request->state)
  1778. {
  1779. if (NULL != dc->rfh)
  1780. {
  1781. /* avoid hanging on to file handle longer than
  1782. * necessary */
  1783. GNUNET_DISK_file_close (dc->rfh);
  1784. dc->rfh = NULL;
  1785. }
  1786. return; /* finished, status update was already done for us */
  1787. }
  1788. }
  1789. if (NULL != dc->rfh)
  1790. {
  1791. /* finally, actually run bottom-up */
  1792. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1793. "Trying bottom-up reconstruction of file `%s'\n",
  1794. dc->filename);
  1795. dc->te =
  1796. GNUNET_FS_tree_encoder_create (dc->h,
  1797. GNUNET_FS_uri_chk_get_file_size (dc->uri),
  1798. dc,
  1799. &fh_reader,
  1800. &reconstruct_cb,
  1801. NULL,
  1802. &reconstruct_cont);
  1803. dc->task = GNUNET_SCHEDULER_add_now (&get_next_block, dc);
  1804. }
  1805. else
  1806. {
  1807. /* simple, top-level download */
  1808. dc->issue_requests = GNUNET_YES;
  1809. schedule_block_download (dc, dc->top_request);
  1810. }
  1811. if (BRS_DOWNLOAD_UP == dc->top_request->state)
  1812. check_completed (dc);
  1813. }
  1814. /**
  1815. * Create SUSPEND event for the given download operation
  1816. * and then clean up our state (without stop signal).
  1817. *
  1818. * @param cls the 'struct GNUNET_FS_DownloadContext' to signal for
  1819. */
  1820. void
  1821. GNUNET_FS_download_signal_suspend_ (void *cls)
  1822. {
  1823. struct GNUNET_FS_DownloadContext *dc = cls;
  1824. struct GNUNET_FS_ProgressInfo pi;
  1825. if (NULL != dc->top)
  1826. GNUNET_FS_end_top (dc->h, dc->top);
  1827. while (NULL != dc->child_head)
  1828. GNUNET_FS_download_signal_suspend_ (dc->child_head);
  1829. if (NULL != dc->search)
  1830. {
  1831. dc->search->download = NULL;
  1832. dc->search = NULL;
  1833. }
  1834. if (NULL != dc->job_queue)
  1835. {
  1836. GNUNET_FS_dequeue_ (dc->job_queue);
  1837. dc->job_queue = NULL;
  1838. }
  1839. if (NULL != dc->parent)
  1840. GNUNET_CONTAINER_DLL_remove (dc->parent->child_head,
  1841. dc->parent->child_tail,
  1842. dc);
  1843. if (NULL != dc->task)
  1844. {
  1845. GNUNET_SCHEDULER_cancel (dc->task);
  1846. dc->task = NULL;
  1847. }
  1848. pi.status = GNUNET_FS_STATUS_DOWNLOAD_SUSPEND;
  1849. GNUNET_FS_download_make_status_ (&pi, dc);
  1850. if (NULL != dc->te)
  1851. {
  1852. GNUNET_FS_tree_encoder_finish (dc->te, NULL);
  1853. dc->te = NULL;
  1854. }
  1855. if (NULL != dc->rfh)
  1856. {
  1857. GNUNET_DISK_file_close (dc->rfh);
  1858. dc->rfh = NULL;
  1859. }
  1860. GNUNET_FS_free_download_request_ (dc->top_request);
  1861. if (NULL != dc->active)
  1862. {
  1863. GNUNET_CONTAINER_multihashmap_destroy (dc->active);
  1864. dc->active = NULL;
  1865. }
  1866. GNUNET_free (dc->filename);
  1867. GNUNET_CONTAINER_meta_data_destroy (dc->meta);
  1868. GNUNET_FS_uri_destroy (dc->uri);
  1869. GNUNET_free (dc->temp_filename);
  1870. GNUNET_free (dc->serialization);
  1871. GNUNET_assert (NULL == dc->job_queue);
  1872. GNUNET_free (dc);
  1873. }
  1874. /**
  1875. * Helper function to setup the download context.
  1876. *
  1877. * @param h handle to the file sharing subsystem
  1878. * @param uri the URI of the file (determines what to download); CHK or LOC URI
  1879. * @param meta known metadata for the file (can be NULL)
  1880. * @param filename where to store the file, maybe NULL (then no file is
  1881. * created on disk and data must be grabbed from the callbacks)
  1882. * @param tempname where to store temporary file data, not used if filename is non-NULL;
  1883. * can be NULL (in which case we will pick a name if needed); the temporary file
  1884. * may already exist, in which case we will try to use the data that is there and
  1885. * if it is not what is desired, will overwrite it
  1886. * @param offset at what offset should we start the download (typically 0)
  1887. * @param length how many bytes should be downloaded starting at offset
  1888. * @param anonymity anonymity level to use for the download
  1889. * @param options various options
  1890. * @param cctx initial value for the client context for this download
  1891. * @return context that can be used to control this download
  1892. */
  1893. struct GNUNET_FS_DownloadContext *
  1894. create_download_context (struct GNUNET_FS_Handle *h,
  1895. const struct GNUNET_FS_Uri *uri,
  1896. const struct GNUNET_CONTAINER_MetaData *meta,
  1897. const char *filename,
  1898. const char *tempname,
  1899. uint64_t offset,
  1900. uint64_t length,
  1901. uint32_t anonymity,
  1902. enum GNUNET_FS_DownloadOptions options,
  1903. void *cctx)
  1904. {
  1905. struct GNUNET_FS_DownloadContext *dc;
  1906. GNUNET_assert (GNUNET_FS_uri_test_chk (uri) || GNUNET_FS_uri_test_loc (uri));
  1907. if ((offset + length < offset) ||
  1908. (offset + length > GNUNET_FS_uri_chk_get_file_size (uri)))
  1909. {
  1910. GNUNET_break (0);
  1911. return NULL;
  1912. }
  1913. dc = GNUNET_new (struct GNUNET_FS_DownloadContext);
  1914. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1915. "Starting download %p, %u bytes at offset %llu\n",
  1916. dc,
  1917. (unsigned int) length,
  1918. (unsigned long long) offset);
  1919. dc->h = h;
  1920. dc->uri = GNUNET_FS_uri_dup (uri);
  1921. dc->meta = GNUNET_CONTAINER_meta_data_duplicate (meta);
  1922. dc->client_info = cctx;
  1923. dc->start_time = GNUNET_TIME_absolute_get ();
  1924. if (NULL != filename)
  1925. {
  1926. dc->filename = GNUNET_strdup (filename);
  1927. if (GNUNET_YES == GNUNET_DISK_file_test (filename))
  1928. GNUNET_break (GNUNET_OK == GNUNET_DISK_file_size (filename,
  1929. &dc->old_file_size,
  1930. GNUNET_YES,
  1931. GNUNET_YES));
  1932. }
  1933. if (GNUNET_FS_uri_test_loc (dc->uri))
  1934. GNUNET_assert (GNUNET_OK ==
  1935. GNUNET_FS_uri_loc_get_peer_identity (dc->uri, &dc->target));
  1936. dc->offset = offset;
  1937. dc->length = length;
  1938. dc->anonymity = anonymity;
  1939. dc->options = options;
  1940. dc->active =
  1941. GNUNET_CONTAINER_multihashmap_create (1 + 2 * (length / DBLOCK_SIZE),
  1942. GNUNET_NO);
  1943. dc->treedepth =
  1944. GNUNET_FS_compute_depth (GNUNET_FS_uri_chk_get_file_size (dc->uri));
  1945. if ((NULL == filename) && (is_recursive_download (dc)))
  1946. {
  1947. if (NULL != tempname)
  1948. dc->temp_filename = GNUNET_strdup (tempname);
  1949. else
  1950. dc->temp_filename = GNUNET_DISK_mktemp ("gnunet-directory-download-tmp");
  1951. }
  1952. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1953. "Starting download `%s' of %llu bytes with tree depth %u\n",
  1954. filename,
  1955. (unsigned long long) length,
  1956. dc->treedepth);
  1957. GNUNET_assert (NULL == dc->job_queue);
  1958. dc->task = GNUNET_SCHEDULER_add_now (&GNUNET_FS_download_start_task_, dc);
  1959. return dc;
  1960. }
  1961. /**
  1962. * Download parts of a file. Note that this will store
  1963. * the blocks at the respective offset in the given file. Also, the
  1964. * download is still using the blocking of the underlying FS
  1965. * encoding. As a result, the download may *write* outside of the
  1966. * given boundaries (if offset and length do not match the 32k FS
  1967. * block boundaries). <p>
  1968. *
  1969. * This function should be used to focus a download towards a
  1970. * particular portion of the file (optimization), not to strictly
  1971. * limit the download to exactly those bytes.
  1972. *
  1973. * @param h handle to the file sharing subsystem
  1974. * @param uri the URI of the file (determines what to download); CHK or LOC URI
  1975. * @param meta known metadata for the file (can be NULL)
  1976. * @param filename where to store the file, maybe NULL (then no file is
  1977. * created on disk and data must be grabbed from the callbacks)
  1978. * @param tempname where to store temporary file data, not used if filename is non-NULL;
  1979. * can be NULL (in which case we will pick a name if needed); the temporary file
  1980. * may already exist, in which case we will try to use the data that is there and
  1981. * if it is not what is desired, will overwrite it
  1982. * @param offset at what offset should we start the download (typically 0)
  1983. * @param length how many bytes should be downloaded starting at offset
  1984. * @param anonymity anonymity level to use for the download
  1985. * @param options various options
  1986. * @param cctx initial value for the client context for this download
  1987. * @param parent parent download to associate this download with (use NULL
  1988. * for top-level downloads; useful for manually-triggered recursive downloads)
  1989. * @return context that can be used to control this download
  1990. */
  1991. struct GNUNET_FS_DownloadContext *
  1992. GNUNET_FS_download_start (struct GNUNET_FS_Handle *h,
  1993. const struct GNUNET_FS_Uri *uri,
  1994. const struct GNUNET_CONTAINER_MetaData *meta,
  1995. const char *filename,
  1996. const char *tempname,
  1997. uint64_t offset,
  1998. uint64_t length,
  1999. uint32_t anonymity,
  2000. enum GNUNET_FS_DownloadOptions options,
  2001. void *cctx,
  2002. struct GNUNET_FS_DownloadContext *parent)
  2003. {
  2004. struct GNUNET_FS_DownloadContext *dc;
  2005. dc = create_download_context (h,
  2006. uri,
  2007. meta,
  2008. filename,
  2009. tempname,
  2010. offset,
  2011. length,
  2012. anonymity,
  2013. options,
  2014. cctx);
  2015. if (NULL == dc)
  2016. return NULL;
  2017. dc->parent = parent;
  2018. if (NULL != parent)
  2019. GNUNET_CONTAINER_DLL_insert (parent->child_head, parent->child_tail, dc);
  2020. else if (0 == (GNUNET_FS_DOWNLOAD_IS_PROBE & options))
  2021. dc->top =
  2022. GNUNET_FS_make_top (dc->h, &GNUNET_FS_download_signal_suspend_, dc);
  2023. return dc;
  2024. }
  2025. /**
  2026. * Download parts of a file based on a search result. The download
  2027. * will be associated with the search result (and the association
  2028. * will be preserved when serializing/deserializing the state).
  2029. * If the search is stopped, the download will not be aborted but
  2030. * be 'promoted' to a stand-alone download.
  2031. *
  2032. * As with the other download function, this will store
  2033. * the blocks at the respective offset in the given file. Also, the
  2034. * download is still using the blocking of the underlying FS
  2035. * encoding. As a result, the download may *write* outside of the
  2036. * given boundaries (if offset and length do not match the 32k FS
  2037. * block boundaries). <p>
  2038. *
  2039. * The given range can be used to focus a download towards a
  2040. * particular portion of the file (optimization), not to strictly
  2041. * limit the download to exactly those bytes.
  2042. *
  2043. * @param h handle to the file sharing subsystem
  2044. * @param sr the search result to use for the download (determines uri and
  2045. * meta data and associations)
  2046. * @param filename where to store the file, maybe NULL (then no file is
  2047. * created on disk and data must be grabbed from the callbacks)
  2048. * @param tempname where to store temporary file data, not used if filename is non-NULL;
  2049. * can be NULL (in which case we will pick a name if needed); the temporary file
  2050. * may already exist, in which case we will try to use the data that is there and
  2051. * if it is not what is desired, will overwrite it
  2052. * @param offset at what offset should we start the download (typically 0)
  2053. * @param length how many bytes should be downloaded starting at offset
  2054. * @param anonymity anonymity level to use for the download
  2055. * @param options various download options
  2056. * @param cctx initial value for the client context for this download
  2057. * @return context that can be used to control this download
  2058. */
  2059. struct GNUNET_FS_DownloadContext *
  2060. GNUNET_FS_download_start_from_search (struct GNUNET_FS_Handle *h,
  2061. struct GNUNET_FS_SearchResult *sr,
  2062. const char *filename,
  2063. const char *tempname,
  2064. uint64_t offset,
  2065. uint64_t length,
  2066. uint32_t anonymity,
  2067. enum GNUNET_FS_DownloadOptions options,
  2068. void *cctx)
  2069. {
  2070. struct GNUNET_FS_DownloadContext *dc;
  2071. if ((NULL == sr) || (NULL != sr->download))
  2072. {
  2073. GNUNET_break (0);
  2074. return NULL;
  2075. }
  2076. dc = create_download_context (h,
  2077. sr->uri,
  2078. sr->meta,
  2079. filename,
  2080. tempname,
  2081. offset,
  2082. length,
  2083. anonymity,
  2084. options,
  2085. cctx);
  2086. if (NULL == dc)
  2087. return NULL;
  2088. dc->search = sr;
  2089. sr->download = dc;
  2090. if (NULL != sr->probe_ctx)
  2091. {
  2092. GNUNET_FS_download_stop (sr->probe_ctx, GNUNET_YES);
  2093. sr->probe_ctx = NULL;
  2094. GNUNET_FS_stop_probe_ping_task_ (sr);
  2095. }
  2096. return dc;
  2097. }
  2098. /**
  2099. * Start the downloading process (by entering the queue).
  2100. *
  2101. * @param dc our download context
  2102. */
  2103. void
  2104. GNUNET_FS_download_start_downloading_ (struct GNUNET_FS_DownloadContext *dc)
  2105. {
  2106. if (dc->completed == dc->length)
  2107. return;
  2108. if (NULL != dc->mq)
  2109. return; /* already running */
  2110. GNUNET_assert (NULL == dc->job_queue);
  2111. GNUNET_assert (NULL == dc->task);
  2112. GNUNET_assert (NULL != dc->active);
  2113. dc->job_queue =
  2114. GNUNET_FS_queue_ (dc->h,
  2115. &activate_fs_download,
  2116. &deactivate_fs_download,
  2117. dc,
  2118. (dc->length + DBLOCK_SIZE - 1) / DBLOCK_SIZE,
  2119. (0 == (dc->options & GNUNET_FS_DOWNLOAD_IS_PROBE))
  2120. ? GNUNET_FS_QUEUE_PRIORITY_NORMAL
  2121. : GNUNET_FS_QUEUE_PRIORITY_PROBE);
  2122. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  2123. "Download %p put into queue as job %p\n",
  2124. dc,
  2125. dc->job_queue);
  2126. }
  2127. /**
  2128. * Suspend a download.
  2129. *
  2130. * @param dc handle for the download
  2131. */
  2132. void
  2133. GNUNET_FS_download_suspend (struct GNUNET_FS_DownloadContext *dc)
  2134. {
  2135. deactivate_fs_download (dc);
  2136. }
  2137. /**
  2138. * Resume a suspended download.
  2139. *
  2140. * @param dc handle for the download
  2141. */
  2142. void
  2143. GNUNET_FS_download_resume (struct GNUNET_FS_DownloadContext *dc)
  2144. {
  2145. struct GNUNET_FS_ProgressInfo pi;
  2146. pi.status = GNUNET_FS_STATUS_DOWNLOAD_ACTIVE;
  2147. GNUNET_FS_download_make_status_ (&pi, dc);
  2148. GNUNET_assert (NULL == dc->task);
  2149. dc->job_queue =
  2150. GNUNET_FS_queue_ (dc->h,
  2151. &activate_fs_download,
  2152. &deactivate_fs_download,
  2153. dc,
  2154. (dc->length + DBLOCK_SIZE - 1) / DBLOCK_SIZE,
  2155. (0 == (dc->options & GNUNET_FS_DOWNLOAD_IS_PROBE))
  2156. ? GNUNET_FS_QUEUE_PRIORITY_NORMAL
  2157. : GNUNET_FS_QUEUE_PRIORITY_PROBE);
  2158. }
  2159. /**
  2160. * Stop a download (aborts if download is incomplete).
  2161. *
  2162. * @param dc handle for the download
  2163. * @param do_delete delete files of incomplete downloads
  2164. */
  2165. void
  2166. GNUNET_FS_download_stop (struct GNUNET_FS_DownloadContext *dc, int do_delete)
  2167. {
  2168. struct GNUNET_FS_ProgressInfo pi;
  2169. int have_children;
  2170. int search_was_null;
  2171. if (NULL != dc->top)
  2172. GNUNET_FS_end_top (dc->h, dc->top);
  2173. if (NULL != dc->task)
  2174. {
  2175. GNUNET_SCHEDULER_cancel (dc->task);
  2176. dc->task = NULL;
  2177. }
  2178. search_was_null = (NULL == dc->search);
  2179. if (NULL != dc->search)
  2180. {
  2181. dc->search->download = NULL;
  2182. GNUNET_FS_search_result_sync_ (dc->search);
  2183. dc->search = NULL;
  2184. }
  2185. if (NULL != dc->job_queue)
  2186. {
  2187. GNUNET_FS_dequeue_ (dc->job_queue);
  2188. dc->job_queue = NULL;
  2189. }
  2190. if (NULL != dc->te)
  2191. {
  2192. GNUNET_FS_tree_encoder_finish (dc->te, NULL);
  2193. dc->te = NULL;
  2194. }
  2195. have_children = (NULL != dc->child_head) ? GNUNET_YES : GNUNET_NO;
  2196. while (NULL != dc->child_head)
  2197. GNUNET_FS_download_stop (dc->child_head, do_delete);
  2198. if (NULL != dc->parent)
  2199. GNUNET_CONTAINER_DLL_remove (dc->parent->child_head,
  2200. dc->parent->child_tail,
  2201. dc);
  2202. if (NULL != dc->serialization)
  2203. GNUNET_FS_remove_sync_file_ (dc->h,
  2204. ((NULL != dc->parent) || (! search_was_null))
  2205. ? GNUNET_FS_SYNC_PATH_CHILD_DOWNLOAD
  2206. : GNUNET_FS_SYNC_PATH_MASTER_DOWNLOAD,
  2207. dc->serialization);
  2208. if ((GNUNET_YES == have_children) && (NULL == dc->parent))
  2209. GNUNET_FS_remove_sync_dir_ (dc->h,
  2210. (! search_was_null)
  2211. ? GNUNET_FS_SYNC_PATH_CHILD_DOWNLOAD
  2212. : GNUNET_FS_SYNC_PATH_MASTER_DOWNLOAD,
  2213. dc->serialization);
  2214. pi.status = GNUNET_FS_STATUS_DOWNLOAD_STOPPED;
  2215. GNUNET_FS_download_make_status_ (&pi, dc);
  2216. GNUNET_FS_free_download_request_ (dc->top_request);
  2217. dc->top_request = NULL;
  2218. if (NULL != dc->active)
  2219. {
  2220. GNUNET_CONTAINER_multihashmap_destroy (dc->active);
  2221. dc->active = NULL;
  2222. }
  2223. if (NULL != dc->filename)
  2224. {
  2225. if ((dc->completed != dc->length) && (GNUNET_YES == do_delete))
  2226. {
  2227. if ((0 != unlink (dc->filename)) && (ENOENT != errno))
  2228. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
  2229. "unlink",
  2230. dc->filename);
  2231. }
  2232. GNUNET_free (dc->filename);
  2233. }
  2234. GNUNET_CONTAINER_meta_data_destroy (dc->meta);
  2235. GNUNET_FS_uri_destroy (dc->uri);
  2236. if (NULL != dc->temp_filename)
  2237. {
  2238. if (0 != unlink (dc->temp_filename))
  2239. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
  2240. "unlink",
  2241. dc->temp_filename);
  2242. GNUNET_free (dc->temp_filename);
  2243. }
  2244. GNUNET_free (dc->serialization);
  2245. GNUNET_assert (NULL == dc->job_queue);
  2246. GNUNET_free (dc);
  2247. }
  2248. /* end of fs_download.c */