2
0

fs_search.c 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759
  1. /*
  2. This file is part of GNUnet.
  3. (C) 2001-2014 Christian Grothoff (and other contributing authors)
  4. GNUnet is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published
  6. by the Free Software Foundation; either version 3, or (at your
  7. option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNUnet; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 59 Tem ple Place - Suite 330,
  15. Boston, MA 02111-1307, USA.
  16. */
  17. /**
  18. * @file fs/fs_search.c
  19. * @brief Helper functions for searching.
  20. * @author Christian Grothoff
  21. */
  22. #include "platform.h"
  23. #include "gnunet_constants.h"
  24. #include "gnunet_fs_service.h"
  25. #include "gnunet_protocols.h"
  26. #include "fs_api.h"
  27. #include "fs_publish_ublock.h"
  28. /**
  29. * Number of availability trials we perform per search result.
  30. */
  31. #define AVAILABILITY_TRIALS_MAX 8
  32. /**
  33. * Fill in all of the generic fields for a search event and
  34. * call the callback.
  35. *
  36. * @param pi structure to fill in
  37. * @param h file-sharing handle
  38. * @param sc overall search context
  39. * @return value returned by the callback
  40. */
  41. void *
  42. GNUNET_FS_search_make_status_ (struct GNUNET_FS_ProgressInfo *pi,
  43. struct GNUNET_FS_Handle *h,
  44. struct GNUNET_FS_SearchContext *sc)
  45. {
  46. void *ret;
  47. pi->value.search.sc = sc;
  48. pi->value.search.cctx = (NULL != sc) ? sc->client_info : NULL;
  49. pi->value.search.pctx =
  50. ((NULL == sc) || (NULL == sc->psearch_result))
  51. ? NULL
  52. : sc->psearch_result->client_info;
  53. pi->value.search.query = (NULL != sc) ? sc->uri : NULL;
  54. pi->value.search.duration = (NULL != sc)
  55. ? GNUNET_TIME_absolute_get_duration (sc->start_time)
  56. : GNUNET_TIME_UNIT_ZERO;
  57. pi->value.search.anonymity = (NULL != sc) ? sc->anonymity : 0;
  58. pi->fsh = h;
  59. ret = h->upcb (h->upcb_cls, pi);
  60. return ret;
  61. }
  62. /**
  63. * Check if the given result is identical to the given URI.
  64. *
  65. * @param cls points to the URI we check against
  66. * @param key not used
  67. * @param value a `struct GNUNET_FS_SearchResult` who's URI we
  68. * should compare with
  69. * @return #GNUNET_SYSERR if the result is present,
  70. * #GNUNET_OK otherwise
  71. */
  72. static int
  73. test_result_present (void *cls,
  74. const struct GNUNET_HashCode * key,
  75. void *value)
  76. {
  77. const struct GNUNET_FS_Uri *uri = cls;
  78. struct GNUNET_FS_SearchResult *sr = value;
  79. if (GNUNET_FS_uri_test_equal (uri, sr->uri))
  80. return GNUNET_SYSERR;
  81. return GNUNET_OK;
  82. }
  83. /**
  84. * We've found a new CHK result. Let the client
  85. * know about it.
  86. *
  87. * @param sc the search context
  88. * @param sr the specific result
  89. */
  90. static void
  91. notify_client_chk_result (struct GNUNET_FS_SearchContext *sc,
  92. struct GNUNET_FS_SearchResult *sr)
  93. {
  94. struct GNUNET_FS_ProgressInfo pi;
  95. pi.status = GNUNET_FS_STATUS_SEARCH_RESULT;
  96. pi.value.search.specifics.result.meta = sr->meta;
  97. pi.value.search.specifics.result.uri = sr->uri;
  98. pi.value.search.specifics.result.result = sr;
  99. pi.value.search.specifics.result.applicability_rank = sr->optional_support;
  100. sr->client_info = GNUNET_FS_search_make_status_ (&pi, sc->h, sc);
  101. }
  102. /**
  103. * We've found new information about an existing CHK result. Let the
  104. * client know about it.
  105. *
  106. * @param sc the search context
  107. * @param sr the specific result
  108. */
  109. static void
  110. notify_client_chk_update (struct GNUNET_FS_SearchContext *sc,
  111. struct GNUNET_FS_SearchResult *sr)
  112. {
  113. struct GNUNET_FS_ProgressInfo pi;
  114. pi.status = GNUNET_FS_STATUS_SEARCH_UPDATE;
  115. pi.value.search.specifics.update.cctx = sr->client_info;
  116. pi.value.search.specifics.update.meta = sr->meta;
  117. pi.value.search.specifics.update.uri = sr->uri;
  118. pi.value.search.specifics.update.availability_rank =
  119. 2 * sr->availability_success - sr->availability_trials;
  120. pi.value.search.specifics.update.availability_certainty =
  121. sr->availability_trials;
  122. pi.value.search.specifics.update.applicability_rank = sr->optional_support;
  123. pi.value.search.specifics.update.current_probe_time
  124. = GNUNET_TIME_absolute_get_duration (sr->probe_active_time);
  125. sr->client_info = GNUNET_FS_search_make_status_ (&pi, sc->h, sc);
  126. }
  127. /**
  128. * Context for "get_result_present".
  129. */
  130. struct GetResultContext
  131. {
  132. /**
  133. * The URI we're looking for.
  134. */
  135. const struct GNUNET_FS_Uri *uri;
  136. /**
  137. * Where to store a pointer to the search
  138. * result struct if we found a match.
  139. */
  140. struct GNUNET_FS_SearchResult *sr;
  141. };
  142. /**
  143. * Check if the given result is identical to the given URI and if so
  144. * return it.
  145. *
  146. * @param cls a `struct GetResultContext`
  147. * @param key not used
  148. * @param value a `struct GNUNET_FS_SearchResult` who's URI we
  149. * should compare with
  150. * @return #GNUNET_OK
  151. */
  152. static int
  153. get_result_present (void *cls, const struct GNUNET_HashCode * key, void *value)
  154. {
  155. struct GetResultContext *grc = cls;
  156. struct GNUNET_FS_SearchResult *sr = value;
  157. if (GNUNET_FS_uri_test_equal (grc->uri, sr->uri))
  158. grc->sr = sr;
  159. return GNUNET_OK;
  160. }
  161. /**
  162. * Signal result of last probe to client and then schedule next
  163. * probe.
  164. *
  165. * @param sr search result to signal for
  166. */
  167. static void
  168. signal_probe_result (struct GNUNET_FS_SearchResult *sr)
  169. {
  170. struct GNUNET_FS_ProgressInfo pi;
  171. pi.status = GNUNET_FS_STATUS_SEARCH_UPDATE;
  172. pi.value.search.specifics.update.cctx = sr->client_info;
  173. pi.value.search.specifics.update.meta = sr->meta;
  174. pi.value.search.specifics.update.uri = sr->uri;
  175. pi.value.search.specifics.update.availability_rank
  176. = 2 * sr->availability_success - sr->availability_trials;
  177. pi.value.search.specifics.update.availability_certainty
  178. = sr->availability_trials;
  179. pi.value.search.specifics.update.applicability_rank = sr->optional_support;
  180. pi.value.search.specifics.update.current_probe_time
  181. = GNUNET_TIME_absolute_get_duration (sr->probe_active_time);
  182. sr->client_info = GNUNET_FS_search_make_status_ (&pi, sr->h, sr->sc);
  183. GNUNET_FS_search_start_probe_ (sr);
  184. }
  185. /**
  186. * Handle the case where we have failed to receive a response for our probe.
  187. *
  188. * @param cls our `struct GNUNET_FS_SearchResult *`
  189. * @param tc scheduler context
  190. */
  191. static void
  192. probe_failure_handler (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  193. {
  194. struct GNUNET_FS_SearchResult *sr = cls;
  195. sr->probe_cancel_task = GNUNET_SCHEDULER_NO_TASK;
  196. sr->availability_trials++;
  197. GNUNET_FS_download_stop (sr->probe_ctx, GNUNET_YES);
  198. sr->probe_ctx = NULL;
  199. if (GNUNET_SCHEDULER_NO_TASK != sr->probe_ping_task)
  200. {
  201. GNUNET_SCHEDULER_cancel (sr->probe_ping_task);
  202. sr->probe_ping_task = GNUNET_SCHEDULER_NO_TASK;
  203. }
  204. GNUNET_FS_search_result_sync_ (sr);
  205. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  206. "Probe #%u for search result %p failed\n",
  207. sr->availability_trials,
  208. sr);
  209. signal_probe_result (sr);
  210. }
  211. /**
  212. * Handle the case where we have gotten a response for our probe.
  213. *
  214. * @param cls our `struct GNUNET_FS_SearchResult *`
  215. * @param tc scheduler context
  216. */
  217. static void
  218. probe_success_handler (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  219. {
  220. struct GNUNET_FS_SearchResult *sr = cls;
  221. sr->probe_cancel_task = GNUNET_SCHEDULER_NO_TASK;
  222. sr->availability_trials++;
  223. sr->availability_success++;
  224. GNUNET_FS_download_stop (sr->probe_ctx, GNUNET_YES);
  225. sr->probe_ctx = NULL;
  226. if (GNUNET_SCHEDULER_NO_TASK != sr->probe_ping_task)
  227. {
  228. GNUNET_SCHEDULER_cancel (sr->probe_ping_task);
  229. sr->probe_ping_task = GNUNET_SCHEDULER_NO_TASK;
  230. }
  231. GNUNET_FS_search_result_sync_ (sr);
  232. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  233. "Probe #%u for search result %p succeeded\n",
  234. sr->availability_trials,
  235. sr);
  236. signal_probe_result (sr);
  237. }
  238. /**
  239. * Notification of FS that a search probe has made progress.
  240. * This function is used INSTEAD of the client's event handler
  241. * for downloads where the #GNUNET_FS_DOWNLOAD_IS_PROBE flag is set.
  242. *
  243. * @param cls closure, always NULL (!), actual closure
  244. * is in the client-context of the info struct
  245. * @param info details about the event, specifying the event type
  246. * and various bits about the event
  247. * @return client-context (for the next progress call
  248. * for this operation; should be set to NULL for
  249. * SUSPEND and STOPPED events). The value returned
  250. * will be passed to future callbacks in the respective
  251. * field in the `struct GNUNET_FS_ProgressInfo`.
  252. */
  253. void *
  254. GNUNET_FS_search_probe_progress_ (void *cls,
  255. const struct GNUNET_FS_ProgressInfo *info)
  256. {
  257. struct GNUNET_FS_SearchResult *sr = info->value.download.cctx;
  258. struct GNUNET_TIME_Relative dur;
  259. switch (info->status)
  260. {
  261. case GNUNET_FS_STATUS_DOWNLOAD_START:
  262. /* ignore */
  263. break;
  264. case GNUNET_FS_STATUS_DOWNLOAD_RESUME:
  265. /* probes should never be resumed */
  266. GNUNET_assert (0);
  267. break;
  268. case GNUNET_FS_STATUS_DOWNLOAD_SUSPEND:
  269. /* probes should never be suspended */
  270. GNUNET_break (0);
  271. break;
  272. case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS:
  273. /* ignore */
  274. break;
  275. case GNUNET_FS_STATUS_DOWNLOAD_ERROR:
  276. if (GNUNET_SCHEDULER_NO_TASK != sr->probe_cancel_task)
  277. {
  278. GNUNET_SCHEDULER_cancel (sr->probe_cancel_task);
  279. sr->probe_cancel_task = GNUNET_SCHEDULER_NO_TASK;
  280. }
  281. sr->probe_cancel_task =
  282. GNUNET_SCHEDULER_add_delayed (sr->remaining_probe_time,
  283. &probe_failure_handler, sr);
  284. break;
  285. case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED:
  286. if (GNUNET_SCHEDULER_NO_TASK != sr->probe_cancel_task)
  287. {
  288. GNUNET_SCHEDULER_cancel (sr->probe_cancel_task);
  289. sr->probe_cancel_task = GNUNET_SCHEDULER_NO_TASK;
  290. }
  291. sr->probe_cancel_task =
  292. GNUNET_SCHEDULER_add_now (&probe_success_handler, sr);
  293. break;
  294. case GNUNET_FS_STATUS_DOWNLOAD_STOPPED:
  295. if (GNUNET_SCHEDULER_NO_TASK != sr->probe_cancel_task)
  296. {
  297. GNUNET_SCHEDULER_cancel (sr->probe_cancel_task);
  298. sr->probe_cancel_task = GNUNET_SCHEDULER_NO_TASK;
  299. }
  300. sr = NULL;
  301. break;
  302. case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE:
  303. if (GNUNET_SCHEDULER_NO_TASK == sr->probe_cancel_task)
  304. {
  305. sr->probe_active_time = GNUNET_TIME_absolute_get ();
  306. sr->probe_cancel_task =
  307. GNUNET_SCHEDULER_add_delayed (sr->remaining_probe_time,
  308. &probe_failure_handler, sr);
  309. }
  310. break;
  311. case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE:
  312. if (GNUNET_SCHEDULER_NO_TASK != sr->probe_cancel_task)
  313. {
  314. GNUNET_SCHEDULER_cancel (sr->probe_cancel_task);
  315. sr->probe_cancel_task = GNUNET_SCHEDULER_NO_TASK;
  316. }
  317. dur = GNUNET_TIME_absolute_get_duration (sr->probe_active_time);
  318. sr->remaining_probe_time =
  319. GNUNET_TIME_relative_subtract (sr->remaining_probe_time, dur);
  320. if (0 == sr->remaining_probe_time.rel_value_us)
  321. sr->probe_cancel_task =
  322. GNUNET_SCHEDULER_add_now (&probe_failure_handler, sr);
  323. GNUNET_FS_search_result_sync_ (sr);
  324. break;
  325. default:
  326. GNUNET_break (0);
  327. return NULL;
  328. }
  329. return sr;
  330. }
  331. /**
  332. * Task run periodically to remind clients that a probe is active.
  333. *
  334. * @param cls the 'struct GNUNET_FS_SearchResult' that we are probing for
  335. * @param tc scheduler context
  336. */
  337. static void
  338. probe_ping_task (void *cls,
  339. const struct GNUNET_SCHEDULER_TaskContext *tc)
  340. {
  341. struct GNUNET_FS_SearchResult *sr = cls;
  342. signal_probe_result (sr);
  343. sr->probe_ping_task
  344. = GNUNET_SCHEDULER_add_delayed (GNUNET_FS_PROBE_UPDATE_FREQUENCY,
  345. &probe_ping_task,
  346. sr);
  347. }
  348. /**
  349. * Start download probes for the given search result.
  350. *
  351. * @param sr the search result
  352. */
  353. void
  354. GNUNET_FS_search_start_probe_ (struct GNUNET_FS_SearchResult *sr)
  355. {
  356. uint64_t off;
  357. uint64_t len;
  358. if (NULL != sr->probe_ctx)
  359. return;
  360. if (NULL != sr->download)
  361. return;
  362. if (0 == (sr->h->flags & GNUNET_FS_FLAGS_DO_PROBES))
  363. return;
  364. if (sr->availability_trials > AVAILABILITY_TRIALS_MAX)
  365. return;
  366. if ( (GNUNET_FS_URI_CHK != sr->uri->type) && (GNUNET_FS_URI_LOC != sr->uri->type))
  367. return;
  368. len = GNUNET_FS_uri_chk_get_file_size (sr->uri);
  369. if (0 == len)
  370. return;
  371. if ((len <= DBLOCK_SIZE) && (sr->availability_success > 0))
  372. return;
  373. off = len / DBLOCK_SIZE;
  374. if (off > 0)
  375. off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, off);
  376. off *= DBLOCK_SIZE;
  377. if (len - off < DBLOCK_SIZE)
  378. len = len - off;
  379. else
  380. len = DBLOCK_SIZE;
  381. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  382. "Starting probe #%u (at offset %llu) for search result %p\n",
  383. sr->availability_trials + 1,
  384. (unsigned long long) off,
  385. sr);
  386. sr->remaining_probe_time =
  387. GNUNET_TIME_relative_multiply (sr->h->avg_block_latency,
  388. 2 * (1 + sr->availability_trials));
  389. sr->probe_ctx =
  390. GNUNET_FS_download_start (sr->h, sr->uri, sr->meta, NULL, NULL, off,
  391. len, sr->anonymity,
  392. GNUNET_FS_DOWNLOAD_NO_TEMPORARIES |
  393. GNUNET_FS_DOWNLOAD_IS_PROBE, sr, NULL);
  394. sr->probe_ping_task
  395. = GNUNET_SCHEDULER_add_now (&probe_ping_task,
  396. sr);
  397. }
  398. /**
  399. * Start download probes for the given search result.
  400. *
  401. * @param h file-sharing handle to use for the operation
  402. * @param uri URI to probe
  403. * @param meta meta data associated with the URI
  404. * @param client_info client info pointer to use for associated events
  405. * @param anonymity anonymity level to use for the probes
  406. * @return the search result handle to access the probe activity
  407. */
  408. struct GNUNET_FS_SearchResult *
  409. GNUNET_FS_probe (struct GNUNET_FS_Handle *h,
  410. const struct GNUNET_FS_Uri *uri,
  411. const struct GNUNET_CONTAINER_MetaData *meta,
  412. void *client_info,
  413. uint32_t anonymity)
  414. {
  415. struct GNUNET_FS_SearchResult *sr;
  416. GNUNET_assert (NULL != h);
  417. sr = GNUNET_new (struct GNUNET_FS_SearchResult);
  418. sr->h = h;
  419. sr->uri = GNUNET_FS_uri_dup (uri);
  420. sr->meta = GNUNET_CONTAINER_meta_data_duplicate (meta);
  421. sr->client_info = client_info;
  422. sr->anonymity = anonymity;
  423. GNUNET_FS_search_start_probe_ (sr);
  424. return sr;
  425. }
  426. /**
  427. * Stop probing activity associated with a search result.
  428. *
  429. * @param sr search result
  430. */
  431. static void
  432. GNUNET_FS_search_stop_probe_ (struct GNUNET_FS_SearchResult *sr)
  433. {
  434. if (NULL != sr->probe_ctx)
  435. {
  436. GNUNET_FS_download_stop (sr->probe_ctx, GNUNET_YES);
  437. sr->probe_ctx = NULL;
  438. }
  439. if (GNUNET_SCHEDULER_NO_TASK != sr->probe_ping_task)
  440. {
  441. GNUNET_SCHEDULER_cancel (sr->probe_ping_task);
  442. sr->probe_ping_task = GNUNET_SCHEDULER_NO_TASK;
  443. }
  444. if (GNUNET_SCHEDULER_NO_TASK != sr->probe_cancel_task)
  445. {
  446. GNUNET_SCHEDULER_cancel (sr->probe_cancel_task);
  447. sr->probe_cancel_task = GNUNET_SCHEDULER_NO_TASK;
  448. }
  449. }
  450. /**
  451. * Stop probe activity. Must ONLY be used on values
  452. * returned from #GNUNET_FS_probe.
  453. *
  454. * @param sr search result to stop probing for (freed)
  455. * @return the value of the 'client_info' pointer
  456. */
  457. void *
  458. GNUNET_FS_probe_stop (struct GNUNET_FS_SearchResult *sr)
  459. {
  460. void *client_info;
  461. GNUNET_assert (NULL == sr->sc);
  462. GNUNET_FS_search_stop_probe_ (sr);
  463. GNUNET_FS_uri_destroy (sr->uri);
  464. GNUNET_CONTAINER_meta_data_destroy (sr->meta);
  465. client_info = sr->client_info;
  466. GNUNET_free (sr);
  467. return client_info;
  468. }
  469. /**
  470. * We have received a KSK result. Check how it fits in with the
  471. * overall query and notify the client accordingly.
  472. *
  473. * @param sc context for the overall query
  474. * @param ent entry for the specific keyword
  475. * @param uri the URI that was found
  476. * @param meta metadata associated with the URI
  477. * under the @a ent keyword
  478. */
  479. static void
  480. process_ksk_result (struct GNUNET_FS_SearchContext *sc,
  481. struct SearchRequestEntry *ent,
  482. const struct GNUNET_FS_Uri *uri,
  483. const struct GNUNET_CONTAINER_MetaData *meta)
  484. {
  485. struct GNUNET_HashCode key;
  486. struct GNUNET_FS_SearchResult *sr;
  487. struct GetResultContext grc;
  488. int is_new;
  489. unsigned int koff;
  490. /* check if new */
  491. GNUNET_assert (NULL != sc);
  492. GNUNET_FS_uri_to_key (uri, &key);
  493. if (GNUNET_SYSERR ==
  494. GNUNET_CONTAINER_multihashmap_get_multiple (ent->results,
  495. &key,
  496. &test_result_present,
  497. (void *) uri))
  498. return; /* duplicate result */
  499. /* try to find search result in master map */
  500. grc.sr = NULL;
  501. grc.uri = uri;
  502. GNUNET_CONTAINER_multihashmap_get_multiple (sc->master_result_map,
  503. &key,
  504. &get_result_present, &grc);
  505. sr = grc.sr;
  506. is_new = (NULL == sr) || (sr->mandatory_missing > 0);
  507. if (NULL == sr)
  508. {
  509. sr = GNUNET_new (struct GNUNET_FS_SearchResult);
  510. sr->h = sc->h;
  511. sr->sc = sc;
  512. sr->anonymity = sc->anonymity;
  513. sr->uri = GNUNET_FS_uri_dup (uri);
  514. sr->meta = GNUNET_CONTAINER_meta_data_duplicate (meta);
  515. sr->mandatory_missing = sc->mandatory_count;
  516. sr->key = key;
  517. sr->keyword_bitmap = GNUNET_malloc ((sc->uri->data.ksk.keywordCount + 7) / 8); /* round up, count bits */
  518. GNUNET_CONTAINER_multihashmap_put (sc->master_result_map, &key, sr,
  519. GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
  520. }
  521. else
  522. {
  523. GNUNET_CONTAINER_meta_data_merge (sr->meta, meta);
  524. }
  525. GNUNET_break (GNUNET_OK ==
  526. GNUNET_CONTAINER_multihashmap_put (ent->results,
  527. &sr->key,
  528. sr,
  529. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  530. koff = ent - sc->requests;
  531. GNUNET_assert ( (ent >= sc->requests) &&
  532. (koff < sc->uri->data.ksk.keywordCount));
  533. sr->keyword_bitmap[koff / 8] |= (1 << (koff % 8));
  534. /* check if mandatory satisfied */
  535. if (1 <= GNUNET_CONTAINER_multihashmap_size (ent->results))
  536. {
  537. if (ent->mandatory)
  538. {
  539. GNUNET_break (sr->mandatory_missing > 0);
  540. sr->mandatory_missing--;
  541. }
  542. else
  543. {
  544. sr->optional_support++;
  545. }
  546. }
  547. if (0 != sr->mandatory_missing)
  548. {
  549. GNUNET_break (NULL == sr->client_info);
  550. return;
  551. }
  552. if (is_new)
  553. notify_client_chk_result (sc, sr);
  554. else
  555. notify_client_chk_update (sc, sr);
  556. GNUNET_FS_search_result_sync_ (sr);
  557. GNUNET_FS_search_start_probe_ (sr);
  558. }
  559. /**
  560. * Start search for content, internal API.
  561. *
  562. * @param h handle to the file sharing subsystem
  563. * @param uri specifies the search parameters; can be
  564. * a KSK URI or an SKS URI.
  565. * @param anonymity desired level of anonymity
  566. * @param options options for the search
  567. * @param cctx client context
  568. * @param psearch parent search result (for namespace update searches)
  569. * @return context that can be used to control the search
  570. */
  571. static struct GNUNET_FS_SearchContext *
  572. search_start (struct GNUNET_FS_Handle *h, const struct GNUNET_FS_Uri *uri,
  573. uint32_t anonymity, enum GNUNET_FS_SearchOptions options,
  574. void *cctx, struct GNUNET_FS_SearchResult *psearch);
  575. /**
  576. * We have received an SKS result. Start searching for updates and
  577. * notify the client if it is a new result.
  578. *
  579. * @param sc context for the overall query
  580. * @param id_update identifier for updates, NULL for none
  581. * @param uri the URI that was found
  582. * @param meta metadata associated with the URI
  583. */
  584. static void
  585. process_sks_result (struct GNUNET_FS_SearchContext *sc,
  586. const char *id_update,
  587. const struct GNUNET_FS_Uri *uri,
  588. const struct GNUNET_CONTAINER_MetaData *meta)
  589. {
  590. struct GNUNET_FS_Uri uu;
  591. struct GNUNET_HashCode key;
  592. struct GNUNET_FS_SearchResult *sr;
  593. /* check if new */
  594. GNUNET_assert (NULL != sc);
  595. GNUNET_FS_uri_to_key (uri, &key);
  596. GNUNET_CRYPTO_hash_xor (&uri->data.chk.chk.key, &uri->data.chk.chk.query,
  597. &key);
  598. if (GNUNET_SYSERR ==
  599. GNUNET_CONTAINER_multihashmap_get_multiple (sc->master_result_map, &key,
  600. &test_result_present,
  601. (void *) uri))
  602. return; /* duplicate result */
  603. sr = GNUNET_new (struct GNUNET_FS_SearchResult);
  604. sr->h = sc->h;
  605. sr->sc = sc;
  606. sr->anonymity = sc->anonymity;
  607. sr->uri = GNUNET_FS_uri_dup (uri);
  608. sr->meta = GNUNET_CONTAINER_meta_data_duplicate (meta);
  609. sr->key = key;
  610. GNUNET_CONTAINER_multihashmap_put (sc->master_result_map, &key, sr,
  611. GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
  612. GNUNET_FS_search_result_sync_ (sr);
  613. GNUNET_FS_search_start_probe_ (sr);
  614. /* notify client */
  615. if (0 == sr->mandatory_missing)
  616. notify_client_chk_result (sc, sr);
  617. else
  618. GNUNET_break (NULL == sr->client_info);
  619. /* search for updates */
  620. if (0 == strlen (id_update))
  621. return; /* no updates */
  622. uu.type = GNUNET_FS_URI_SKS;
  623. uu.data.sks.ns = sc->uri->data.sks.ns;
  624. uu.data.sks.identifier = GNUNET_strdup (id_update);
  625. (void) search_start (sc->h, &uu, sc->anonymity, sc->options, NULL, sr);
  626. GNUNET_free (uu.data.sks.identifier);
  627. }
  628. /**
  629. * Decrypt a ublock using a 'keyword' as the passphrase. Given the
  630. * KSK public key derived from the keyword, this function looks up
  631. * the original keyword in the search context and decrypts the
  632. * given ciphertext block.
  633. *
  634. * @param sc search context with the keywords
  635. * @param dpub derived public key used for the search
  636. * @param edata encrypted data
  637. * @param edata_size number of bytes in @a edata (and @a data)
  638. * @param data where to store the plaintext
  639. * @return keyword index on success, #GNUNET_SYSERR on error (no such
  640. * keyword, internal error)
  641. */
  642. static int
  643. decrypt_block_with_keyword (const struct GNUNET_FS_SearchContext *sc,
  644. const struct GNUNET_CRYPTO_EcdsaPublicKey *dpub,
  645. const void *edata,
  646. size_t edata_size,
  647. char *data)
  648. {
  649. const struct GNUNET_CRYPTO_EcdsaPrivateKey *anon;
  650. struct GNUNET_CRYPTO_EcdsaPublicKey anon_pub;
  651. unsigned int i;
  652. /* find key */
  653. for (i = 0; i < sc->uri->data.ksk.keywordCount; i++)
  654. if (0 == memcmp (dpub,
  655. &sc->requests[i].dpub,
  656. sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
  657. break;
  658. if (i == sc->uri->data.ksk.keywordCount)
  659. {
  660. /* oops, does not match any of our keywords!? */
  661. GNUNET_break (0);
  662. return GNUNET_SYSERR;
  663. }
  664. /* decrypt */
  665. anon = GNUNET_CRYPTO_ecdsa_key_get_anonymous ();
  666. GNUNET_CRYPTO_ecdsa_key_get_public (anon, &anon_pub);
  667. GNUNET_FS_ublock_decrypt_ (edata, edata_size,
  668. &anon_pub,
  669. sc->requests[i].keyword,
  670. data);
  671. return i;
  672. }
  673. /**
  674. * Process a keyword search result. The actual type of block is
  675. * a UBlock; we know it is a keyword search result because that's
  676. * what we were searching for.
  677. *
  678. * @param sc our search context
  679. * @param ub the ublock with the keyword search result
  680. * @param size size of @a ub
  681. */
  682. static void
  683. process_kblock (struct GNUNET_FS_SearchContext *sc,
  684. const struct UBlock *ub,
  685. size_t size)
  686. {
  687. size_t j;
  688. char pt[size - sizeof (struct UBlock)];
  689. const char *eos;
  690. struct GNUNET_CONTAINER_MetaData *meta;
  691. struct GNUNET_FS_Uri *uri;
  692. char *emsg;
  693. int i;
  694. if (-1 == (i = decrypt_block_with_keyword (sc,
  695. &ub->verification_key,
  696. &ub[1],
  697. size - sizeof (struct UBlock),
  698. pt)))
  699. return;
  700. /* parse; pt[0] is just '\0', so we skip over that */
  701. eos = memchr (&pt[1], '\0', sizeof (pt) - 1);
  702. if (NULL == eos)
  703. {
  704. GNUNET_break_op (0);
  705. return;
  706. }
  707. if (NULL == (uri = GNUNET_FS_uri_parse (&pt[1], &emsg)))
  708. {
  709. if (GNUNET_FS_VERSION > 0x00090400)
  710. {
  711. /* we broke this in 0x00090300, so don't bitch
  712. too loudly just one version up... */
  713. GNUNET_break_op (0); /* ublock malformed */
  714. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  715. _("Failed to parse URI `%s': %s\n"),
  716. &pt[1],
  717. emsg);
  718. }
  719. GNUNET_free_non_null (emsg);
  720. return;
  721. }
  722. j = eos - pt + 1;
  723. if (sizeof (pt) == j)
  724. meta = GNUNET_CONTAINER_meta_data_create ();
  725. else
  726. meta = GNUNET_CONTAINER_meta_data_deserialize (&pt[j], sizeof (pt) - j);
  727. if (NULL == meta)
  728. {
  729. GNUNET_break_op (0); /* ublock malformed */
  730. GNUNET_FS_uri_destroy (uri);
  731. return;
  732. }
  733. process_ksk_result (sc,
  734. &sc->requests[i],
  735. uri,
  736. meta);
  737. /* clean up */
  738. GNUNET_CONTAINER_meta_data_destroy (meta);
  739. GNUNET_FS_uri_destroy (uri);
  740. }
  741. /**
  742. * Process a namespace-search result. The actual type of block is
  743. * a UBlock; we know it is a namespace search result because that's
  744. * what we were searching for.
  745. *
  746. * @param sc our search context
  747. * @param ub the ublock with a namespace result
  748. * @param size size of @a ub
  749. */
  750. static void
  751. process_sblock (struct GNUNET_FS_SearchContext *sc,
  752. const struct UBlock *ub,
  753. size_t size)
  754. {
  755. size_t len = size - sizeof (struct UBlock);
  756. char pt[len];
  757. struct GNUNET_FS_Uri *uri;
  758. struct GNUNET_CONTAINER_MetaData *meta;
  759. const char *id;
  760. const char *uris;
  761. size_t off;
  762. char *emsg;
  763. GNUNET_FS_ublock_decrypt_ (&ub[1], len,
  764. &sc->uri->data.sks.ns,
  765. sc->uri->data.sks.identifier,
  766. pt);
  767. /* parse */
  768. if (0 == (off = GNUNET_STRINGS_buffer_tokenize (pt, len, 2, &id, &uris)))
  769. {
  770. GNUNET_break_op (0); /* ublock malformed */
  771. return;
  772. }
  773. if (NULL == (meta = GNUNET_CONTAINER_meta_data_deserialize (&pt[off], len - off)))
  774. {
  775. GNUNET_break_op (0); /* ublock malformed */
  776. return;
  777. }
  778. if (NULL == (uri = GNUNET_FS_uri_parse (uris, &emsg)))
  779. {
  780. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  781. _("Failed to parse URI `%s': %s\n"),
  782. uris, emsg);
  783. GNUNET_break_op (0); /* ublock malformed */
  784. GNUNET_free_non_null (emsg);
  785. GNUNET_CONTAINER_meta_data_destroy (meta);
  786. return;
  787. }
  788. /* process */
  789. process_sks_result (sc, id, uri, meta);
  790. /* clean up */
  791. GNUNET_FS_uri_destroy (uri);
  792. GNUNET_CONTAINER_meta_data_destroy (meta);
  793. }
  794. /**
  795. * Process a search result.
  796. *
  797. * @param sc our search context
  798. * @param type type of the result
  799. * @param expiration when it will expire
  800. * @param data the (encrypted) response
  801. * @param size size of @a data
  802. */
  803. static void
  804. process_result (struct GNUNET_FS_SearchContext *sc,
  805. enum GNUNET_BLOCK_Type type,
  806. struct GNUNET_TIME_Absolute expiration,
  807. const void *data,
  808. size_t size)
  809. {
  810. if (GNUNET_TIME_absolute_get_duration (expiration).rel_value_us > 0)
  811. {
  812. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  813. "Result received has already expired.\n");
  814. return; /* result expired */
  815. }
  816. switch (type)
  817. {
  818. case GNUNET_BLOCK_TYPE_FS_UBLOCK:
  819. if (GNUNET_FS_URI_SKS == sc->uri->type)
  820. process_sblock (sc, data, size);
  821. else
  822. process_kblock (sc, data, size);
  823. break;
  824. case GNUNET_BLOCK_TYPE_ANY:
  825. GNUNET_break (0);
  826. break;
  827. case GNUNET_BLOCK_TYPE_FS_DBLOCK:
  828. GNUNET_break (0);
  829. break;
  830. case GNUNET_BLOCK_TYPE_FS_ONDEMAND:
  831. GNUNET_break (0);
  832. break;
  833. case GNUNET_BLOCK_TYPE_FS_IBLOCK:
  834. GNUNET_break (0);
  835. break;
  836. default:
  837. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  838. _("Got result with unknown block type `%d', ignoring"), type);
  839. break;
  840. }
  841. }
  842. /**
  843. * Shutdown any existing connection to the FS
  844. * service and try to establish a fresh one
  845. * (and then re-transmit our search request).
  846. *
  847. * @param sc the search to reconnec
  848. */
  849. static void
  850. try_reconnect (struct GNUNET_FS_SearchContext *sc);
  851. /**
  852. * Type of a function to call when we receive a message
  853. * from the service.
  854. *
  855. * @param cls closure
  856. * @param msg message received, NULL on timeout or fatal error
  857. */
  858. static void
  859. receive_results (void *cls, const struct GNUNET_MessageHeader *msg)
  860. {
  861. struct GNUNET_FS_SearchContext *sc = cls;
  862. const struct ClientPutMessage *cm;
  863. uint16_t msize;
  864. if ((NULL == msg) || (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_FS_PUT) ||
  865. (ntohs (msg->size) <= sizeof (struct ClientPutMessage)))
  866. {
  867. try_reconnect (sc);
  868. return;
  869. }
  870. msize = ntohs (msg->size);
  871. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  872. "Receiving %u bytes of result from fs service\n", msize);
  873. cm = (const struct ClientPutMessage *) msg;
  874. process_result (sc, ntohl (cm->type),
  875. GNUNET_TIME_absolute_ntoh (cm->expiration), &cm[1],
  876. msize - sizeof (struct ClientPutMessage));
  877. /* continue receiving */
  878. GNUNET_CLIENT_receive (sc->client, &receive_results, sc,
  879. GNUNET_TIME_UNIT_FOREVER_REL);
  880. }
  881. /**
  882. * Schedule the transmission of the (next) search request
  883. * to the service.
  884. *
  885. * @param sc context for the search
  886. */
  887. static void
  888. schedule_transmit_search_request (struct GNUNET_FS_SearchContext *sc);
  889. /**
  890. * Closure for 'build_result_set'.
  891. */
  892. struct MessageBuilderContext
  893. {
  894. /**
  895. * How many entries can we store to xoff.
  896. */
  897. unsigned int put_cnt;
  898. /**
  899. * How many entries should we skip.
  900. */
  901. unsigned int skip_cnt;
  902. /**
  903. * Where to store the keys.
  904. */
  905. struct GNUNET_HashCode *xoff;
  906. /**
  907. * Search context we are iterating for.
  908. */
  909. struct GNUNET_FS_SearchContext *sc;
  910. /**
  911. * Keyword offset the search result must match (0 for SKS)
  912. */
  913. unsigned int keyword_offset;
  914. };
  915. /**
  916. * Iterating over the known results, pick those matching the given
  917. * result range and store their keys at 'xoff'.
  918. *
  919. * @param cls the `struct MessageBuilderContext`
  920. * @param key key for a result
  921. * @param value the search result
  922. * @return #GNUNET_OK to continue iterating
  923. */
  924. static int
  925. build_result_set (void *cls,
  926. const struct GNUNET_HashCode *key,
  927. void *value)
  928. {
  929. struct MessageBuilderContext *mbc = cls;
  930. struct GNUNET_FS_SearchResult *sr = value;
  931. if ( (NULL != sr->keyword_bitmap) &&
  932. (0 == (sr->keyword_bitmap[mbc->keyword_offset / 8] & (1 << (mbc->keyword_offset % 8)))) )
  933. return GNUNET_OK; /* have no match for this keyword yet */
  934. if (mbc->skip_cnt > 0)
  935. {
  936. mbc->skip_cnt--;
  937. return GNUNET_OK;
  938. }
  939. if (0 == mbc->put_cnt)
  940. return GNUNET_SYSERR;
  941. mbc->sc->search_request_map_offset++;
  942. mbc->xoff[--mbc->put_cnt] = *key;
  943. return GNUNET_OK;
  944. }
  945. /**
  946. * Iterating over the known results, count those matching the given
  947. * result range and increment put count for each.
  948. *
  949. * @param cls the `struct MessageBuilderContext`
  950. * @param key key for a result
  951. * @param value the search result
  952. * @return #GNUNET_OK to continue iterating
  953. */
  954. static int
  955. find_result_set (void *cls,
  956. const struct GNUNET_HashCode *key,
  957. void *value)
  958. {
  959. struct MessageBuilderContext *mbc = cls;
  960. struct GNUNET_FS_SearchResult *sr = value;
  961. if ( (NULL != sr->keyword_bitmap) &&
  962. (0 == (sr->keyword_bitmap[mbc->keyword_offset / 8] & (1 << (mbc->keyword_offset % 8)))) )
  963. return GNUNET_OK; /* have no match for this keyword yet */
  964. mbc->put_cnt++;
  965. return GNUNET_OK;
  966. }
  967. /**
  968. * We're ready to transmit the search request to the file-sharing
  969. * service. Do it. If the request is too large to fit into a single
  970. * message, transmit in increments.
  971. *
  972. * @param cls closure
  973. * @param size number of bytes available in @a buf
  974. * @param buf where the callee should write the message
  975. * @return number of bytes written to @a buf
  976. */
  977. static size_t
  978. transmit_search_request (void *cls, size_t size, void *buf)
  979. {
  980. struct GNUNET_FS_SearchContext *sc = cls;
  981. struct MessageBuilderContext mbc;
  982. size_t msize;
  983. struct SearchMessage *sm;
  984. struct GNUNET_CRYPTO_EcdsaPublicKey dpub;
  985. unsigned int total_seen_results; /* total number of result hashes to send */
  986. unsigned int message_size_limit;
  987. uint32_t options;
  988. if (NULL == buf)
  989. {
  990. try_reconnect (sc);
  991. return 0;
  992. }
  993. mbc.sc = sc;
  994. mbc.skip_cnt = sc->search_request_map_offset;
  995. sm = buf;
  996. sm->header.type = htons (GNUNET_MESSAGE_TYPE_FS_START_SEARCH);
  997. mbc.xoff = (struct GNUNET_HashCode *) &sm[1];
  998. options = SEARCH_MESSAGE_OPTION_NONE;
  999. if (0 != (sc->options & GNUNET_FS_SEARCH_OPTION_LOOPBACK_ONLY))
  1000. options |= SEARCH_MESSAGE_OPTION_LOOPBACK_ONLY;
  1001. if (GNUNET_FS_uri_test_ksk (sc->uri))
  1002. {
  1003. msize = sizeof (struct SearchMessage);
  1004. GNUNET_assert (size >= msize);
  1005. mbc.keyword_offset = sc->keyword_offset;
  1006. /* calculate total number of known results (in put_cnt => total_seen_results) */
  1007. mbc.put_cnt = 0;
  1008. GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map,
  1009. &find_result_set, &mbc);
  1010. total_seen_results = mbc.put_cnt;
  1011. /* calculate how many results we can send in this message */
  1012. message_size_limit = (size - msize) / sizeof (struct GNUNET_HashCode);
  1013. mbc.put_cnt = GNUNET_MIN (message_size_limit,
  1014. total_seen_results - mbc.skip_cnt);
  1015. if (sc->search_request_map_offset < total_seen_results)
  1016. GNUNET_assert (mbc.put_cnt > 0);
  1017. /* now build message */
  1018. msize += sizeof (struct GNUNET_HashCode) * mbc.put_cnt;
  1019. sm->header.size = htons (msize);
  1020. sm->type = htonl (GNUNET_BLOCK_TYPE_FS_UBLOCK);
  1021. sm->anonymity_level = htonl (sc->anonymity);
  1022. memset (&sm->target, 0, sizeof (struct GNUNET_PeerIdentity));
  1023. sm->query = sc->requests[sc->keyword_offset].uquery;
  1024. GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map,
  1025. &build_result_set, &mbc);
  1026. GNUNET_assert (0 == mbc.put_cnt);
  1027. GNUNET_assert (total_seen_results >= sc->search_request_map_offset);
  1028. if (total_seen_results != sc->search_request_map_offset)
  1029. {
  1030. /* more requesting to be done... */
  1031. sm->options = htonl (options | SEARCH_MESSAGE_OPTION_CONTINUED);
  1032. schedule_transmit_search_request (sc);
  1033. return msize;
  1034. }
  1035. sm->options = htonl (options);
  1036. sc->keyword_offset++;
  1037. sc->search_request_map_offset = 0;
  1038. if (sc->uri->data.ksk.keywordCount != sc->keyword_offset)
  1039. {
  1040. /* more requesting to be done... */
  1041. schedule_transmit_search_request (sc);
  1042. return msize;
  1043. }
  1044. }
  1045. else
  1046. {
  1047. GNUNET_assert (GNUNET_FS_uri_test_sks (sc->uri));
  1048. msize = sizeof (struct SearchMessage);
  1049. GNUNET_assert (size >= msize);
  1050. sm->type = htonl (GNUNET_BLOCK_TYPE_FS_UBLOCK);
  1051. sm->anonymity_level = htonl (sc->anonymity);
  1052. memset (&sm->target, 0, sizeof (struct GNUNET_PeerIdentity));
  1053. GNUNET_CRYPTO_ecdsa_public_key_derive (&sc->uri->data.sks.ns,
  1054. sc->uri->data.sks.identifier,
  1055. "fs-ublock",
  1056. &dpub);
  1057. GNUNET_CRYPTO_hash (&dpub,
  1058. sizeof (dpub),
  1059. &sm->query);
  1060. message_size_limit = (size - msize) / sizeof (struct GNUNET_HashCode);
  1061. total_seen_results = GNUNET_CONTAINER_multihashmap_size (sc->master_result_map);
  1062. mbc.put_cnt = GNUNET_MIN (message_size_limit,
  1063. total_seen_results - mbc.skip_cnt);
  1064. mbc.keyword_offset = 0;
  1065. if (sc->search_request_map_offset < total_seen_results)
  1066. GNUNET_assert (mbc.put_cnt > 0);
  1067. msize += sizeof (struct GNUNET_HashCode) * mbc.put_cnt;
  1068. GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map,
  1069. &build_result_set, &mbc);
  1070. sm->header.size = htons (msize);
  1071. GNUNET_assert (total_seen_results >= sc->search_request_map_offset);
  1072. if (total_seen_results != sc->search_request_map_offset)
  1073. {
  1074. /* more requesting to be done... */
  1075. sm->options = htonl (options | SEARCH_MESSAGE_OPTION_CONTINUED);
  1076. schedule_transmit_search_request (sc);
  1077. return msize;
  1078. }
  1079. sm->options = htonl (options);
  1080. }
  1081. GNUNET_CLIENT_receive (sc->client,
  1082. &receive_results, sc,
  1083. GNUNET_TIME_UNIT_FOREVER_REL);
  1084. return msize;
  1085. }
  1086. /**
  1087. * Schedule the transmission of the (next) search request
  1088. * to the service.
  1089. *
  1090. * @param sc context for the search
  1091. */
  1092. static void
  1093. schedule_transmit_search_request (struct GNUNET_FS_SearchContext *sc)
  1094. {
  1095. size_t size;
  1096. unsigned int left;
  1097. unsigned int fit;
  1098. unsigned int request;
  1099. size = sizeof (struct SearchMessage);
  1100. left =
  1101. GNUNET_CONTAINER_multihashmap_size (sc->master_result_map) -
  1102. sc->search_request_map_offset;
  1103. fit = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - size) / sizeof (struct GNUNET_HashCode);
  1104. request = GNUNET_MIN (fit, left);
  1105. size += sizeof (struct GNUNET_HashCode) * request;
  1106. GNUNET_CLIENT_notify_transmit_ready (sc->client, size,
  1107. GNUNET_CONSTANTS_SERVICE_TIMEOUT,
  1108. GNUNET_NO,
  1109. &transmit_search_request, sc);
  1110. }
  1111. /**
  1112. * Reconnect to the FS service and transmit
  1113. * our queries NOW.
  1114. *
  1115. * @param cls our search context
  1116. * @param tc unused
  1117. */
  1118. static void
  1119. do_reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  1120. {
  1121. struct GNUNET_FS_SearchContext *sc = cls;
  1122. struct GNUNET_CLIENT_Connection *client;
  1123. sc->task = GNUNET_SCHEDULER_NO_TASK;
  1124. client = GNUNET_CLIENT_connect ("fs", sc->h->cfg);
  1125. if (NULL == client)
  1126. {
  1127. try_reconnect (sc);
  1128. return;
  1129. }
  1130. sc->client = client;
  1131. sc->search_request_map_offset = 0;
  1132. sc->keyword_offset = 0;
  1133. schedule_transmit_search_request (sc);
  1134. }
  1135. /**
  1136. * Shutdown any existing connection to the FS
  1137. * service and try to establish a fresh one
  1138. * (and then re-transmit our search request).
  1139. *
  1140. * @param sc the search to reconnec
  1141. */
  1142. static void
  1143. try_reconnect (struct GNUNET_FS_SearchContext *sc)
  1144. {
  1145. if (NULL != sc->client)
  1146. {
  1147. GNUNET_CLIENT_disconnect (sc->client);
  1148. sc->client = NULL;
  1149. }
  1150. sc->reconnect_backoff = GNUNET_TIME_STD_BACKOFF (sc->reconnect_backoff);
  1151. sc->task =
  1152. GNUNET_SCHEDULER_add_delayed (sc->reconnect_backoff,
  1153. &do_reconnect,
  1154. sc);
  1155. }
  1156. /**
  1157. * Start search for content, internal API.
  1158. *
  1159. * @param h handle to the file sharing subsystem
  1160. * @param uri specifies the search parameters; can be
  1161. * a KSK URI or an SKS URI.
  1162. * @param anonymity desired level of anonymity
  1163. * @param options options for the search
  1164. * @param cctx initial value for the client context
  1165. * @param psearch parent search result (for namespace update searches)
  1166. * @return context that can be used to control the search
  1167. */
  1168. static struct GNUNET_FS_SearchContext *
  1169. search_start (struct GNUNET_FS_Handle *h,
  1170. const struct GNUNET_FS_Uri *uri,
  1171. uint32_t anonymity,
  1172. enum GNUNET_FS_SearchOptions options,
  1173. void *cctx,
  1174. struct GNUNET_FS_SearchResult *psearch)
  1175. {
  1176. struct GNUNET_FS_SearchContext *sc;
  1177. struct GNUNET_FS_ProgressInfo pi;
  1178. sc = GNUNET_new (struct GNUNET_FS_SearchContext);
  1179. sc->h = h;
  1180. sc->options = options;
  1181. sc->uri = GNUNET_FS_uri_dup (uri);
  1182. sc->anonymity = anonymity;
  1183. sc->start_time = GNUNET_TIME_absolute_get ();
  1184. if (NULL != psearch)
  1185. {
  1186. sc->psearch_result = psearch;
  1187. psearch->update_search = sc;
  1188. }
  1189. sc->master_result_map = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_NO);
  1190. sc->client_info = cctx;
  1191. if (GNUNET_OK != GNUNET_FS_search_start_searching_ (sc))
  1192. {
  1193. GNUNET_FS_uri_destroy (sc->uri);
  1194. GNUNET_CONTAINER_multihashmap_destroy (sc->master_result_map);
  1195. GNUNET_free (sc);
  1196. return NULL;
  1197. }
  1198. GNUNET_FS_search_sync_ (sc);
  1199. pi.status = GNUNET_FS_STATUS_SEARCH_START;
  1200. sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc->h, sc);
  1201. return sc;
  1202. }
  1203. /**
  1204. * Update the 'results' map for the individual keywords with the
  1205. * results from the 'global' result set.
  1206. *
  1207. * @param cls closure, the `struct GNUNET_FS_SearchContext *`
  1208. * @param key current key code
  1209. * @param value value in the hash map, the `struct GNUNET_FS_SearchResult *`
  1210. * @return #GNUNET_YES (we should continue to iterate)
  1211. */
  1212. static int
  1213. update_sre_result_maps (void *cls,
  1214. const struct GNUNET_HashCode *key,
  1215. void *value)
  1216. {
  1217. struct GNUNET_FS_SearchContext *sc = cls;
  1218. struct GNUNET_FS_SearchResult *sr = value;
  1219. unsigned int i;
  1220. for (i = 0; i < sc->uri->data.ksk.keywordCount; i++)
  1221. if (0 != (sr->keyword_bitmap[i / 8] & (1 << (i % 8))))
  1222. GNUNET_break (GNUNET_OK ==
  1223. GNUNET_CONTAINER_multihashmap_put (sc->requests[i].results,
  1224. &sr->key,
  1225. sr,
  1226. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  1227. return GNUNET_YES;
  1228. }
  1229. /**
  1230. * Build the request and actually initiate the search using the
  1231. * GNUnet FS service.
  1232. *
  1233. * @param sc search context
  1234. * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  1235. */
  1236. int
  1237. GNUNET_FS_search_start_searching_ (struct GNUNET_FS_SearchContext *sc)
  1238. {
  1239. unsigned int i;
  1240. const char *keyword;
  1241. const struct GNUNET_CRYPTO_EcdsaPrivateKey *anon;
  1242. struct GNUNET_CRYPTO_EcdsaPublicKey anon_pub;
  1243. struct SearchRequestEntry *sre;
  1244. GNUNET_assert (NULL == sc->client);
  1245. if (GNUNET_FS_uri_test_ksk (sc->uri))
  1246. {
  1247. GNUNET_assert (0 != sc->uri->data.ksk.keywordCount);
  1248. anon = GNUNET_CRYPTO_ecdsa_key_get_anonymous ();
  1249. GNUNET_CRYPTO_ecdsa_key_get_public (anon, &anon_pub);
  1250. sc->requests =
  1251. GNUNET_malloc (sizeof (struct SearchRequestEntry) *
  1252. sc->uri->data.ksk.keywordCount);
  1253. for (i = 0; i < sc->uri->data.ksk.keywordCount; i++)
  1254. {
  1255. keyword = &sc->uri->data.ksk.keywords[i][1];
  1256. sre = &sc->requests[i];
  1257. sre->keyword = GNUNET_strdup (keyword);
  1258. GNUNET_CRYPTO_ecdsa_public_key_derive (&anon_pub,
  1259. keyword,
  1260. "fs-ublock",
  1261. &sre->dpub);
  1262. GNUNET_CRYPTO_hash (&sre->dpub,
  1263. sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
  1264. &sre->uquery);
  1265. sre->mandatory = (sc->uri->data.ksk.keywords[i][0] == '+');
  1266. if (sre->mandatory)
  1267. sc->mandatory_count++;
  1268. sre->results = GNUNET_CONTAINER_multihashmap_create (4, GNUNET_NO);
  1269. }
  1270. GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map,
  1271. &update_sre_result_maps,
  1272. sc);
  1273. }
  1274. sc->client = GNUNET_CLIENT_connect ("fs", sc->h->cfg);
  1275. if (NULL == sc->client)
  1276. return GNUNET_SYSERR;
  1277. sc->search_request_map_offset = 0;
  1278. schedule_transmit_search_request (sc);
  1279. return GNUNET_OK;
  1280. }
  1281. /**
  1282. * Freeze probes for the given search result.
  1283. *
  1284. * @param cls the global FS handle
  1285. * @param key the key for the search result (unused)
  1286. * @param value the search result to free
  1287. * @return #GNUNET_OK
  1288. */
  1289. static int
  1290. search_result_freeze_probes (void *cls,
  1291. const struct GNUNET_HashCode *key,
  1292. void *value)
  1293. {
  1294. struct GNUNET_FS_SearchResult *sr = value;
  1295. if (NULL != sr->probe_ctx)
  1296. {
  1297. GNUNET_FS_download_stop (sr->probe_ctx, GNUNET_YES);
  1298. sr->probe_ctx = NULL;
  1299. }
  1300. if (GNUNET_SCHEDULER_NO_TASK != sr->probe_ping_task)
  1301. {
  1302. GNUNET_SCHEDULER_cancel (sr->probe_ping_task);
  1303. sr->probe_ping_task = GNUNET_SCHEDULER_NO_TASK;
  1304. }
  1305. if (GNUNET_SCHEDULER_NO_TASK != sr->probe_cancel_task)
  1306. {
  1307. GNUNET_SCHEDULER_cancel (sr->probe_cancel_task);
  1308. sr->probe_cancel_task = GNUNET_SCHEDULER_NO_TASK;
  1309. }
  1310. if (NULL != sr->update_search)
  1311. GNUNET_FS_search_pause (sr->update_search);
  1312. return GNUNET_OK;
  1313. }
  1314. /**
  1315. * Resume probes for the given search result.
  1316. *
  1317. * @param cls the global FS handle
  1318. * @param key the key for the search result (unused)
  1319. * @param value the search result to free
  1320. * @return #GNUNET_OK
  1321. */
  1322. static int
  1323. search_result_resume_probes (void *cls,
  1324. const struct GNUNET_HashCode * key,
  1325. void *value)
  1326. {
  1327. struct GNUNET_FS_SearchResult *sr = value;
  1328. GNUNET_FS_search_start_probe_ (sr);
  1329. if (NULL != sr->update_search)
  1330. GNUNET_FS_search_continue (sr->update_search);
  1331. return GNUNET_OK;
  1332. }
  1333. /**
  1334. * Signal suspend and free the given search result.
  1335. *
  1336. * @param cls the global FS handle
  1337. * @param key the key for the search result (unused)
  1338. * @param value the search result to free
  1339. * @return #GNUNET_OK
  1340. */
  1341. static int
  1342. search_result_suspend (void *cls,
  1343. const struct GNUNET_HashCode *key,
  1344. void *value)
  1345. {
  1346. struct GNUNET_FS_SearchContext *sc = cls;
  1347. struct GNUNET_FS_SearchResult *sr = value;
  1348. struct GNUNET_FS_ProgressInfo pi;
  1349. if (NULL != sr->download)
  1350. {
  1351. GNUNET_FS_download_signal_suspend_ (sr->download);
  1352. sr->download = NULL;
  1353. }
  1354. if (NULL != sr->update_search)
  1355. {
  1356. GNUNET_FS_search_signal_suspend_ (sr->update_search);
  1357. sr->update_search = NULL;
  1358. }
  1359. GNUNET_FS_search_stop_probe_ (sr);
  1360. if (0 == sr->mandatory_missing)
  1361. {
  1362. /* client is aware of search result, notify about suspension event */
  1363. pi.status = GNUNET_FS_STATUS_SEARCH_RESULT_SUSPEND;
  1364. pi.value.search.specifics.result_suspend.cctx = sr->client_info;
  1365. pi.value.search.specifics.result_suspend.meta = sr->meta;
  1366. pi.value.search.specifics.result_suspend.uri = sr->uri;
  1367. sr->client_info = GNUNET_FS_search_make_status_ (&pi, sc->h, sc);
  1368. }
  1369. GNUNET_break (NULL == sr->client_info);
  1370. GNUNET_free_non_null (sr->serialization);
  1371. GNUNET_FS_uri_destroy (sr->uri);
  1372. GNUNET_CONTAINER_meta_data_destroy (sr->meta);
  1373. GNUNET_free_non_null (sr->keyword_bitmap);
  1374. GNUNET_free (sr);
  1375. return GNUNET_OK;
  1376. }
  1377. /**
  1378. * Create SUSPEND event for the given search operation
  1379. * and then clean up our state (without stop signal).
  1380. *
  1381. * @param cls the `struct GNUNET_FS_SearchContext` to signal for
  1382. */
  1383. void
  1384. GNUNET_FS_search_signal_suspend_ (void *cls)
  1385. {
  1386. struct GNUNET_FS_SearchContext *sc = cls;
  1387. struct GNUNET_FS_ProgressInfo pi;
  1388. unsigned int i;
  1389. GNUNET_FS_end_top (sc->h, sc->top);
  1390. GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map,
  1391. &search_result_suspend, sc);
  1392. pi.status = GNUNET_FS_STATUS_SEARCH_SUSPEND;
  1393. sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc->h, sc);
  1394. GNUNET_break (NULL == sc->client_info);
  1395. if (sc->task != GNUNET_SCHEDULER_NO_TASK)
  1396. {
  1397. GNUNET_SCHEDULER_cancel (sc->task);
  1398. sc->task = GNUNET_SCHEDULER_NO_TASK;
  1399. }
  1400. if (NULL != sc->client)
  1401. {
  1402. GNUNET_CLIENT_disconnect (sc->client);
  1403. sc->client = NULL;
  1404. }
  1405. GNUNET_CONTAINER_multihashmap_destroy (sc->master_result_map);
  1406. if (NULL != sc->requests)
  1407. {
  1408. GNUNET_assert (GNUNET_FS_uri_test_ksk (sc->uri));
  1409. for (i = 0; i < sc->uri->data.ksk.keywordCount; i++)
  1410. {
  1411. GNUNET_CONTAINER_multihashmap_destroy (sc->requests[i].results);
  1412. GNUNET_free (sc->requests[i].keyword);
  1413. }
  1414. }
  1415. GNUNET_free_non_null (sc->requests);
  1416. GNUNET_free_non_null (sc->emsg);
  1417. GNUNET_FS_uri_destroy (sc->uri);
  1418. GNUNET_free_non_null (sc->serialization);
  1419. GNUNET_free (sc);
  1420. }
  1421. /**
  1422. * Start search for content.
  1423. *
  1424. * @param h handle to the file sharing subsystem
  1425. * @param uri specifies the search parameters; can be
  1426. * a KSK URI or an SKS URI.
  1427. * @param anonymity desired level of anonymity
  1428. * @param options options for the search
  1429. * @param cctx initial value for the client context
  1430. * @return context that can be used to control the search
  1431. */
  1432. struct GNUNET_FS_SearchContext *
  1433. GNUNET_FS_search_start (struct GNUNET_FS_Handle *h,
  1434. const struct GNUNET_FS_Uri *uri, uint32_t anonymity,
  1435. enum GNUNET_FS_SearchOptions options, void *cctx)
  1436. {
  1437. struct GNUNET_FS_SearchContext *ret;
  1438. ret = search_start (h, uri, anonymity, options, cctx, NULL);
  1439. if (NULL == ret)
  1440. return NULL;
  1441. ret->top = GNUNET_FS_make_top (h, &GNUNET_FS_search_signal_suspend_, ret);
  1442. return ret;
  1443. }
  1444. /**
  1445. * Pause search.
  1446. *
  1447. * @param sc context for the search that should be paused
  1448. */
  1449. void
  1450. GNUNET_FS_search_pause (struct GNUNET_FS_SearchContext *sc)
  1451. {
  1452. struct GNUNET_FS_ProgressInfo pi;
  1453. if (GNUNET_SCHEDULER_NO_TASK != sc->task)
  1454. {
  1455. GNUNET_SCHEDULER_cancel (sc->task);
  1456. sc->task = GNUNET_SCHEDULER_NO_TASK;
  1457. }
  1458. if (NULL != sc->client)
  1459. GNUNET_CLIENT_disconnect (sc->client);
  1460. sc->client = NULL;
  1461. GNUNET_FS_search_sync_ (sc);
  1462. GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map,
  1463. &search_result_freeze_probes, sc);
  1464. pi.status = GNUNET_FS_STATUS_SEARCH_PAUSED;
  1465. sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc->h, sc);
  1466. }
  1467. /**
  1468. * Continue paused search.
  1469. *
  1470. * @param sc context for the search that should be resumed
  1471. */
  1472. void
  1473. GNUNET_FS_search_continue (struct GNUNET_FS_SearchContext *sc)
  1474. {
  1475. struct GNUNET_FS_ProgressInfo pi;
  1476. GNUNET_assert (NULL == sc->client);
  1477. GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == sc->task);
  1478. do_reconnect (sc, NULL);
  1479. GNUNET_FS_search_sync_ (sc);
  1480. pi.status = GNUNET_FS_STATUS_SEARCH_CONTINUED;
  1481. sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc->h, sc);
  1482. GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map,
  1483. &search_result_resume_probes, sc);
  1484. }
  1485. /**
  1486. * Signal stop for the given search result.
  1487. *
  1488. * @param cls the global FS handle
  1489. * @param key the key for the search result (unused)
  1490. * @param value the search result to free
  1491. * @return #GNUNET_OK
  1492. */
  1493. static int
  1494. search_result_stop (void *cls,
  1495. const struct GNUNET_HashCode *key,
  1496. void *value)
  1497. {
  1498. struct GNUNET_FS_SearchContext *sc = cls;
  1499. struct GNUNET_FS_SearchResult *sr = value;
  1500. struct GNUNET_FS_ProgressInfo pi;
  1501. GNUNET_FS_search_stop_probe_ (sr);
  1502. if (NULL != sr->download)
  1503. {
  1504. sr->download->search = NULL;
  1505. sr->download->top =
  1506. GNUNET_FS_make_top (sr->download->h,
  1507. &GNUNET_FS_download_signal_suspend_,
  1508. sr->download);
  1509. if (NULL != sr->download->serialization)
  1510. {
  1511. GNUNET_FS_remove_sync_file_ (sc->h,
  1512. GNUNET_FS_SYNC_PATH_CHILD_DOWNLOAD,
  1513. sr->download->serialization);
  1514. GNUNET_free (sr->download->serialization);
  1515. sr->download->serialization = NULL;
  1516. }
  1517. pi.status = GNUNET_FS_STATUS_DOWNLOAD_LOST_PARENT;
  1518. GNUNET_FS_download_make_status_ (&pi, sr->download);
  1519. GNUNET_FS_download_sync_ (sr->download);
  1520. sr->download = NULL;
  1521. }
  1522. if (0 != sr->mandatory_missing)
  1523. {
  1524. /* client is unaware of search result as
  1525. it does not match required keywords */
  1526. GNUNET_break (NULL == sr->client_info);
  1527. return GNUNET_OK;
  1528. }
  1529. pi.status = GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED;
  1530. pi.value.search.specifics.result_stopped.cctx = sr->client_info;
  1531. pi.value.search.specifics.result_stopped.meta = sr->meta;
  1532. pi.value.search.specifics.result_stopped.uri = sr->uri;
  1533. sr->client_info = GNUNET_FS_search_make_status_ (&pi, sr->h, sc);
  1534. return GNUNET_OK;
  1535. }
  1536. /**
  1537. * Free the given search result.
  1538. *
  1539. * @param cls the global FS handle
  1540. * @param key the key for the search result (unused)
  1541. * @param value the search result to free
  1542. * @return #GNUNET_OK
  1543. */
  1544. static int
  1545. search_result_free (void *cls,
  1546. const struct GNUNET_HashCode *key,
  1547. void *value)
  1548. {
  1549. struct GNUNET_FS_SearchResult *sr = value;
  1550. if (NULL != sr->update_search)
  1551. {
  1552. GNUNET_FS_search_stop (sr->update_search);
  1553. GNUNET_assert (NULL == sr->update_search);
  1554. }
  1555. GNUNET_break (NULL == sr->probe_ctx);
  1556. GNUNET_break (GNUNET_SCHEDULER_NO_TASK == sr->probe_cancel_task);
  1557. GNUNET_break (GNUNET_SCHEDULER_NO_TASK == sr->probe_ping_task);
  1558. GNUNET_break (NULL == sr->client_info);
  1559. GNUNET_free_non_null (sr->serialization);
  1560. GNUNET_FS_uri_destroy (sr->uri);
  1561. GNUNET_CONTAINER_meta_data_destroy (sr->meta);
  1562. GNUNET_free_non_null (sr->keyword_bitmap);
  1563. GNUNET_free (sr);
  1564. return GNUNET_OK;
  1565. }
  1566. /**
  1567. * Stop search for content.
  1568. *
  1569. * @param sc context for the search that should be stopped
  1570. */
  1571. void
  1572. GNUNET_FS_search_stop (struct GNUNET_FS_SearchContext *sc)
  1573. {
  1574. struct GNUNET_FS_ProgressInfo pi;
  1575. unsigned int i;
  1576. if (NULL != sc->top)
  1577. GNUNET_FS_end_top (sc->h, sc->top);
  1578. GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map,
  1579. &search_result_stop, sc);
  1580. if (NULL != sc->psearch_result)
  1581. sc->psearch_result->update_search = NULL;
  1582. if (NULL != sc->serialization)
  1583. {
  1584. GNUNET_FS_remove_sync_file_ (sc->h,
  1585. (sc->psearch_result !=
  1586. NULL) ? GNUNET_FS_SYNC_PATH_CHILD_SEARCH :
  1587. GNUNET_FS_SYNC_PATH_MASTER_SEARCH,
  1588. sc->serialization);
  1589. GNUNET_FS_remove_sync_dir_ (sc->h,
  1590. (sc->psearch_result !=
  1591. NULL) ? GNUNET_FS_SYNC_PATH_CHILD_SEARCH :
  1592. GNUNET_FS_SYNC_PATH_MASTER_SEARCH,
  1593. sc->serialization);
  1594. GNUNET_free (sc->serialization);
  1595. }
  1596. pi.status = GNUNET_FS_STATUS_SEARCH_STOPPED;
  1597. sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc->h, sc);
  1598. GNUNET_break (NULL == sc->client_info);
  1599. if (GNUNET_SCHEDULER_NO_TASK != sc->task)
  1600. GNUNET_SCHEDULER_cancel (sc->task);
  1601. if (NULL != sc->client)
  1602. GNUNET_CLIENT_disconnect (sc->client);
  1603. GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map,
  1604. &search_result_free, sc);
  1605. GNUNET_CONTAINER_multihashmap_destroy (sc->master_result_map);
  1606. if (NULL != sc->requests)
  1607. {
  1608. GNUNET_assert (GNUNET_FS_uri_test_ksk (sc->uri));
  1609. for (i = 0; i < sc->uri->data.ksk.keywordCount; i++)
  1610. GNUNET_CONTAINER_multihashmap_destroy (sc->requests[i].results);
  1611. }
  1612. GNUNET_free_non_null (sc->requests);
  1613. GNUNET_free_non_null (sc->emsg);
  1614. GNUNET_FS_uri_destroy (sc->uri);
  1615. GNUNET_free (sc);
  1616. }
  1617. /* end of fs_search.c */