2 This file is part of GNUnet.
3 (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file fs/fs_search.c
23 * @brief Helper functions for searching.
24 * @author Christian Grothoff
27 * - handle namespace advertisements (NBlocks, see FIXME;
28 * note that we currently use KBLOCK instead of ANY when
29 * searching => NBLOCKS would not fit! FIX this as well!)
30 * - add support for pushing "already seen" information
31 * to FS service for bloomfilter (can wait)
32 * - handle availability probes (can wait)
33 * - make operations persistent (can wait)
37 #include "gnunet_constants.h"
38 #include "gnunet_fs_service.h"
39 #include "gnunet_protocols.h"
42 #define DEBUG_SEARCH GNUNET_NO
47 * Fill in all of the generic fields for
50 * @param pi structure to fill in
51 * @param sc overall search context
54 make_search_status (struct GNUNET_FS_ProgressInfo *pi,
55 struct GNUNET_FS_SearchContext *sc)
57 pi->value.search.sc = sc;
61 = (sc->parent == NULL) ? NULL : sc->parent->client_info;
62 pi->value.search.query
64 pi->value.search.duration = GNUNET_TIME_absolute_get_duration (sc->start_time);
65 pi->value.search.anonymity = sc->anonymity;
70 * Check if the given result is identical
73 * @param cls points to the URI we check against
75 * @param value a "struct SearchResult" who's URI we
77 * @return GNUNET_SYSERR if the result is present,
81 test_result_present (void *cls,
82 const GNUNET_HashCode * key,
85 const struct GNUNET_FS_Uri *uri = cls;
86 struct SearchResult *sr = value;
88 if (GNUNET_FS_uri_test_equal (uri,
96 * We've found a new CHK result. Let the client
99 * @param sc the search context
100 * @param sr the specific result
103 notify_client_chk_result (struct GNUNET_FS_SearchContext *sc,
104 struct SearchResult *sr)
106 struct GNUNET_FS_ProgressInfo pi;
108 pi.status = GNUNET_FS_STATUS_SEARCH_RESULT;
109 make_search_status (&pi, sc);
110 pi.value.search.specifics.result.meta = sr->meta;
111 pi.value.search.specifics.result.uri = sr->uri;
112 sr->client_info = sc->h->upcb (sc->h->upcb_cls,
118 * We've found new information about an existing CHK result. Let the
119 * client know about it.
121 * @param sc the search context
122 * @param sr the specific result
125 notify_client_chk_update (struct GNUNET_FS_SearchContext *sc,
126 struct SearchResult *sr)
128 struct GNUNET_FS_ProgressInfo pi;
130 pi.status = GNUNET_FS_STATUS_SEARCH_UPDATE;
131 make_search_status (&pi, sc);
132 pi.value.search.specifics.update.cctx = sr->client_info;
133 pi.value.search.specifics.update.meta = sr->meta;
134 pi.value.search.specifics.update.uri = sr->uri;
135 pi.value.search.specifics.update.availability_rank
136 = 2*sr->availability_success - sr->availability_trials;
137 pi.value.search.specifics.update.availability_certainty
138 = sr->availability_trials;
139 pi.value.search.specifics.update.applicability_rank
140 = sr->optional_support;
141 sr->client_info = sc->h->upcb (sc->h->upcb_cls,
147 * Context for "get_result_present".
149 struct GetResultContext
152 * The URI we're looking for.
154 const struct GNUNET_FS_Uri *uri;
157 * Where to store a pointer to the search
158 * result struct if we found a match.
160 struct SearchResult *sr;
165 * Check if the given result is identical to the given URI and if so
168 * @param cls a "struct GetResultContext"
169 * @param key not used
170 * @param value a "struct SearchResult" who's URI we
171 * should compare with
175 get_result_present (void *cls,
176 const GNUNET_HashCode * key,
179 struct GetResultContext *grc = cls;
180 struct SearchResult *sr = value;
182 if (GNUNET_FS_uri_test_equal (grc->uri,
190 * We have received a KSK result. Check how it fits in with the
191 * overall query and notify the client accordingly.
193 * @param sc context for the overall query
194 * @param ent entry for the specific keyword
195 * @param uri the URI that was found
196 * @param meta metadata associated with the URI
197 * under the "ent" keyword
200 process_ksk_result (struct GNUNET_FS_SearchContext *sc,
201 struct SearchRequestEntry *ent,
202 const struct GNUNET_FS_Uri *uri,
203 const struct GNUNET_CONTAINER_MetaData *meta)
206 struct SearchResult *sr;
207 struct GetResultContext grc;
211 GNUNET_FS_uri_to_key (uri, &key);
213 GNUNET_CONTAINER_multihashmap_get_multiple (ent->results,
215 &test_result_present,
217 return; /* duplicate result */
218 /* try to find search result in master map */
221 GNUNET_CONTAINER_multihashmap_get_multiple (sc->master_result_map,
226 is_new = (NULL == sr) || (sr->mandatory_missing > 0);
229 sr = GNUNET_malloc (sizeof (struct SearchResult));
230 sr->uri = GNUNET_FS_uri_dup (uri);
231 sr->meta = GNUNET_CONTAINER_meta_data_duplicate (meta);
232 sr->mandatory_missing = sc->mandatory_count;
233 GNUNET_CONTAINER_multihashmap_put (sc->master_result_map,
236 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
240 /* FIXME: consider combining the meta data */
242 /* check if mandatory satisfied */
244 sr->mandatory_missing--;
246 sr->optional_support++;
247 if (0 != sr->mandatory_missing)
250 notify_client_chk_result (sc, sr);
252 notify_client_chk_update (sc, sr);
253 /* FIXME: consider starting probes for "sr" */
258 * Start search for content, internal API.
260 * @param h handle to the file sharing subsystem
261 * @param uri specifies the search parameters; can be
262 * a KSK URI or an SKS URI.
263 * @param anonymity desired level of anonymity
264 * @param cctx client context
265 * @param parent parent search (for namespace update searches)
266 * @return context that can be used to control the search
268 static struct GNUNET_FS_SearchContext *
269 search_start (struct GNUNET_FS_Handle *h,
270 const struct GNUNET_FS_Uri *uri,
273 struct GNUNET_FS_SearchContext *parent);
277 * We have received an SKS result. Start searching for updates and
278 * notify the client if it is a new result.
280 * @param sc context for the overall query
281 * @param id_update identifier for updates, NULL for none
282 * @param uri the URI that was found
283 * @param meta metadata associated with the URI
286 process_sks_result (struct GNUNET_FS_SearchContext *sc,
287 const char *id_update,
288 const struct GNUNET_FS_Uri *uri,
289 const struct GNUNET_CONTAINER_MetaData *meta)
291 struct GNUNET_FS_Uri uu;
293 struct SearchResult *sr;
296 GNUNET_FS_uri_to_key (uri, &key);
297 GNUNET_CRYPTO_hash_xor (&uri->data.chk.chk.key,
298 &uri->data.chk.chk.query,
301 GNUNET_CONTAINER_multihashmap_get_multiple (sc->master_result_map,
303 &test_result_present,
305 return; /* duplicate result */
306 sr = GNUNET_malloc (sizeof (struct SearchResult));
307 sr->uri = GNUNET_FS_uri_dup (uri);
308 sr->meta = GNUNET_CONTAINER_meta_data_duplicate (meta);
309 GNUNET_CONTAINER_multihashmap_put (sc->master_result_map,
312 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
313 /* FIXME: consider starting probes for "sr" */
316 notify_client_chk_result (sc, sr);
317 /* search for updates */
318 if (strlen (id_update) == 0)
319 return; /* no updates */
321 uu.data.sks.namespace = sc->uri->data.sks.namespace;
322 uu.data.sks.identifier = GNUNET_strdup (id_update);
323 /* FIXME: should attach update search
324 to the individual result, not
325 the entire SKS search! */
335 * Process a keyword-search result.
337 * @param sc our search context
338 * @param kb the kblock
339 * @param size size of kb
342 process_kblock (struct GNUNET_FS_SearchContext *sc,
343 const struct KBlock *kb,
349 char pt[size - sizeof (struct KBlock)];
350 struct GNUNET_CRYPTO_AesSessionKey skey;
351 struct GNUNET_CRYPTO_AesInitializationVector iv;
353 struct GNUNET_CONTAINER_MetaData *meta;
354 struct GNUNET_FS_Uri *uri;
357 GNUNET_CRYPTO_hash (&kb->keyspace,
358 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
361 for (i=0;i<sc->uri->data.ksk.keywordCount;i++)
363 &sc->requests[i].query,
364 sizeof (GNUNET_HashCode)))
366 if (i == sc->uri->data.ksk.keywordCount)
368 /* oops, does not match any of our keywords!? */
373 GNUNET_CRYPTO_hash_to_aes_key (&sc->requests[i].key, &skey, &iv);
374 GNUNET_CRYPTO_aes_decrypt (&kb[1],
375 size - sizeof (struct KBlock),
380 eos = memchr (pt, 0, sizeof (pt));
387 if (sizeof (pt) == j)
388 meta = GNUNET_CONTAINER_meta_data_create ();
390 meta = GNUNET_CONTAINER_meta_data_deserialize (&pt[j],
394 GNUNET_break_op (0); /* kblock malformed */
397 uri = GNUNET_FS_uri_parse (pt, &emsg);
400 GNUNET_break_op (0); /* kblock malformed */
401 GNUNET_free_non_null (emsg);
402 GNUNET_CONTAINER_meta_data_destroy (meta);
406 process_ksk_result (sc, &sc->requests[i], uri, meta);
409 GNUNET_CONTAINER_meta_data_destroy (meta);
410 GNUNET_FS_uri_destroy (uri);
415 * Process a namespace-search result.
417 * @param sc our search context
418 * @param sb the sblock
419 * @param size size of sb
422 process_sblock (struct GNUNET_FS_SearchContext *sc,
423 const struct SBlock *sb,
426 size_t len = size - sizeof (struct SBlock);
428 struct GNUNET_CRYPTO_AesSessionKey skey;
429 struct GNUNET_CRYPTO_AesInitializationVector iv;
430 struct GNUNET_FS_Uri *uri;
431 struct GNUNET_CONTAINER_MetaData *meta;
440 identifier = sc->uri->data.sks.identifier;
441 GNUNET_CRYPTO_hash (identifier,
444 GNUNET_CRYPTO_hash_to_aes_key (&key, &skey, &iv);
445 GNUNET_CRYPTO_aes_decrypt (&sb[1],
451 off = GNUNET_STRINGS_buffer_tokenize (pt,
458 GNUNET_break_op (0); /* sblock malformed */
461 meta = GNUNET_CONTAINER_meta_data_deserialize (&pt[off],
465 GNUNET_break_op (0); /* sblock malformed */
468 uri = GNUNET_FS_uri_parse (uris, &emsg);
471 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
472 "Failed to parse URI `%s': %s\n",
474 GNUNET_break_op (0); /* sblock malformed */
475 GNUNET_free_non_null (emsg);
476 GNUNET_CONTAINER_meta_data_destroy (meta);
480 process_sks_result (sc, id, uri, meta);
482 GNUNET_FS_uri_destroy (uri);
483 GNUNET_CONTAINER_meta_data_destroy (meta);
488 * Process a search result.
490 * @param sc our search context
491 * @param type type of the result
492 * @param expiration when it will expire
493 * @param data the (encrypted) response
494 * @param size size of data
497 process_result (struct GNUNET_FS_SearchContext *sc,
499 struct GNUNET_TIME_Absolute expiration,
503 if (GNUNET_TIME_absolute_get_duration (expiration).value > 0)
505 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
506 "Result received has already expired.\n");
507 return; /* result expired */
511 case GNUNET_DATASTORE_BLOCKTYPE_KBLOCK:
512 if (! GNUNET_FS_uri_test_ksk (sc->uri))
517 if (sizeof (struct KBlock) > size)
522 process_kblock (sc, data, size);
524 case GNUNET_DATASTORE_BLOCKTYPE_SBLOCK:
525 if (! GNUNET_FS_uri_test_sks (sc->uri))
530 if (sizeof (struct SBlock) > size)
535 process_sblock (sc, data, size);
537 case GNUNET_DATASTORE_BLOCKTYPE_NBLOCK:
538 GNUNET_break (0); // FIXME: not implemented!
540 case GNUNET_DATASTORE_BLOCKTYPE_ANY:
541 case GNUNET_DATASTORE_BLOCKTYPE_DBLOCK:
542 case GNUNET_DATASTORE_BLOCKTYPE_ONDEMAND:
543 case GNUNET_DATASTORE_BLOCKTYPE_IBLOCK:
547 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
548 _("Got result with unknown block type `%d', ignoring"),
556 * Shutdown any existing connection to the FS
557 * service and try to establish a fresh one
558 * (and then re-transmit our search request).
560 * @param sc the search to reconnec
563 try_reconnect (struct GNUNET_FS_SearchContext *sc);
567 * Type of a function to call when we receive a message
571 * @param msg message received, NULL on timeout or fatal error
574 receive_results (void *cls,
575 const struct GNUNET_MessageHeader * msg)
577 struct GNUNET_FS_SearchContext *sc = cls;
578 const struct PutMessage *cm;
581 if ( (NULL == msg) ||
582 (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_FS_PUT) ||
583 (ntohs (msg->size) <= sizeof (struct PutMessage)) )
588 msize = ntohs (msg->size);
589 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
590 "Receiving %u bytes of result from fs service\n",
592 cm = (const struct PutMessage*) msg;
595 GNUNET_TIME_absolute_ntoh (cm->expiration),
597 msize - sizeof (struct PutMessage));
598 /* continue receiving */
599 GNUNET_CLIENT_receive (sc->client,
602 GNUNET_TIME_UNIT_FOREVER_REL);
607 * We're ready to transmit the search request to the
608 * file-sharing service. Do it.
611 * @param size number of bytes available in buf
612 * @param buf where the callee should write the message
613 * @return number of bytes written to buf
616 transmit_search_request (void *cls,
620 struct GNUNET_FS_SearchContext *sc = cls;
622 struct SearchMessage *sm;
624 const char *identifier;
633 if (GNUNET_FS_uri_test_ksk (sc->uri))
635 msize = sizeof (struct SearchMessage) * sc->uri->data.ksk.keywordCount;
636 GNUNET_assert (size >= msize);
638 memset (sm, 0, msize);
639 for (i=0;i<sc->uri->data.ksk.keywordCount;i++)
641 sm[i].header.size = htons (sizeof (struct SearchMessage));
642 sm[i].header.type = htons (GNUNET_MESSAGE_TYPE_FS_START_SEARCH);
643 sm[i].type = htonl (GNUNET_DATASTORE_BLOCKTYPE_KBLOCK);
644 sm[i].anonymity_level = htonl (sc->anonymity);
645 sm[i].query = sc->requests[i].query;
650 GNUNET_assert (GNUNET_FS_uri_test_sks (sc->uri));
651 msize = sizeof (struct SearchMessage);
652 GNUNET_assert (size >= msize);
654 memset (sm, 0, msize);
655 sm->header.size = htons (sizeof (struct SearchMessage));
656 sm->header.type = htons (GNUNET_MESSAGE_TYPE_FS_START_SEARCH);
657 sm->type = htonl (GNUNET_DATASTORE_BLOCKTYPE_SBLOCK);
658 sm->anonymity_level = htonl (sc->anonymity);
659 sm->target = sc->uri->data.sks.namespace;
660 identifier = sc->uri->data.sks.identifier;
661 GNUNET_CRYPTO_hash (identifier,
664 GNUNET_CRYPTO_hash (&key,
665 sizeof (GNUNET_HashCode),
667 GNUNET_CRYPTO_hash_xor (&idh,
671 GNUNET_CLIENT_receive (sc->client,
674 GNUNET_TIME_UNIT_FOREVER_REL);
680 * Reconnect to the FS service and transmit
683 * @param cls our search context
687 do_reconnect (void *cls,
688 const struct GNUNET_SCHEDULER_TaskContext *tc)
690 struct GNUNET_FS_SearchContext *sc = cls;
691 struct GNUNET_CLIENT_Connection *client;
694 sc->task = GNUNET_SCHEDULER_NO_TASK;
695 client = GNUNET_CLIENT_connect (sc->h->sched,
704 if (GNUNET_FS_uri_test_ksk (sc->uri))
705 size = sizeof (struct SearchMessage) * sc->uri->data.ksk.keywordCount;
707 size = sizeof (struct SearchMessage);
708 GNUNET_CLIENT_notify_transmit_ready (client,
710 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
712 &transmit_search_request,
718 * Shutdown any existing connection to the FS
719 * service and try to establish a fresh one
720 * (and then re-transmit our search request).
722 * @param sc the search to reconnec
725 try_reconnect (struct GNUNET_FS_SearchContext *sc)
727 if (NULL != sc->client)
729 GNUNET_CLIENT_disconnect (sc->client, GNUNET_NO);
733 = GNUNET_SCHEDULER_add_delayed (sc->h->sched,
734 GNUNET_TIME_UNIT_SECONDS,
741 * Start search for content, internal API.
743 * @param h handle to the file sharing subsystem
744 * @param uri specifies the search parameters; can be
745 * a KSK URI or an SKS URI.
746 * @param anonymity desired level of anonymity
747 * @param cctx initial value for the client context
748 * @param parent parent search (for namespace update searches)
749 * @return context that can be used to control the search
751 static struct GNUNET_FS_SearchContext *
752 search_start (struct GNUNET_FS_Handle *h,
753 const struct GNUNET_FS_Uri *uri,
756 struct GNUNET_FS_SearchContext *parent)
758 struct GNUNET_FS_SearchContext *sc;
759 struct GNUNET_CLIENT_Connection *client;
760 struct GNUNET_FS_ProgressInfo pi;
765 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub;
766 struct GNUNET_CRYPTO_RsaPrivateKey *pk;
768 if (GNUNET_FS_uri_test_ksk (uri))
770 size = sizeof (struct SearchMessage) * uri->data.ksk.keywordCount;
774 GNUNET_assert (GNUNET_FS_uri_test_sks (uri));
775 size = sizeof (struct SearchMessage);
777 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
779 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
780 _("Too many keywords specified for a single search."));
783 client = GNUNET_CLIENT_connect (h->sched,
788 sc = GNUNET_malloc (sizeof(struct GNUNET_FS_SearchContext));
790 sc->uri = GNUNET_FS_uri_dup (uri);
791 sc->anonymity = anonymity;
792 sc->start_time = GNUNET_TIME_absolute_get ();
795 sc->master_result_map = GNUNET_CONTAINER_multihashmap_create (16);
796 sc->client_info = cctx;
797 if (GNUNET_FS_uri_test_ksk (uri))
799 GNUNET_assert (0 != sc->uri->data.ksk.keywordCount);
800 sc->requests = GNUNET_malloc (sizeof (struct SearchRequestEntry) *
801 sc->uri->data.ksk.keywordCount);
802 for (i=0;i<sc->uri->data.ksk.keywordCount;i++)
804 keyword = &sc->uri->data.ksk.keywords[i][1];
805 GNUNET_CRYPTO_hash (keyword, strlen (keyword), &hc);
806 pk = GNUNET_CRYPTO_rsa_key_create_from_hash (&hc);
807 GNUNET_CRYPTO_rsa_key_get_public (pk, &pub);
808 GNUNET_CRYPTO_rsa_key_free (pk);
809 GNUNET_CRYPTO_hash (&pub,
810 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
811 &sc->requests[i].query);
812 sc->requests[i].mandatory = (sc->uri->data.ksk.keywords[i][0] == '+');
813 if (sc->requests[i].mandatory)
814 sc->mandatory_count++;
815 sc->requests[i].results = GNUNET_CONTAINER_multihashmap_create (4);
816 GNUNET_CRYPTO_hash (keyword,
818 &sc->requests[i].key);
822 GNUNET_CONTAINER_DLL_insert (parent->child_head,
825 pi.status = GNUNET_FS_STATUS_SEARCH_START;
826 make_search_status (&pi, sc);
827 sc->client_info = h->upcb (h->upcb_cls,
829 GNUNET_CLIENT_notify_transmit_ready (client,
831 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
833 &transmit_search_request,
840 * Start search for content.
842 * @param h handle to the file sharing subsystem
843 * @param uri specifies the search parameters; can be
844 * a KSK URI or an SKS URI.
845 * @param anonymity desired level of anonymity
846 * @param cctx initial value for the client context
847 * @return context that can be used to control the search
849 struct GNUNET_FS_SearchContext *
850 GNUNET_FS_search_start (struct GNUNET_FS_Handle *h,
851 const struct GNUNET_FS_Uri *uri,
855 return search_start (h, uri, anonymity, cctx, NULL);
862 * @param sc context for the search that should be paused
865 GNUNET_FS_search_pause (struct GNUNET_FS_SearchContext *sc)
867 struct GNUNET_FS_ProgressInfo pi;
869 if (sc->task != GNUNET_SCHEDULER_NO_TASK)
870 GNUNET_SCHEDULER_cancel (sc->h->sched,
872 sc->task = GNUNET_SCHEDULER_NO_TASK;
873 if (NULL != sc->client)
874 GNUNET_CLIENT_disconnect (sc->client, GNUNET_NO);
876 // FIXME: make persistent!
877 // FIXME: should this freeze all active probes?
878 pi.status = GNUNET_FS_STATUS_SEARCH_PAUSED;
879 make_search_status (&pi, sc);
880 sc->client_info = sc->h->upcb (sc->h->upcb_cls,
886 * Continue paused search.
888 * @param sc context for the search that should be resumed
891 GNUNET_FS_search_continue (struct GNUNET_FS_SearchContext *sc)
893 struct GNUNET_FS_ProgressInfo pi;
895 GNUNET_assert (sc->client == NULL);
896 GNUNET_assert (sc->task == GNUNET_SCHEDULER_NO_TASK);
897 do_reconnect (sc, NULL);
898 // FIXME: make persistent!
899 pi.status = GNUNET_FS_STATUS_SEARCH_CONTINUED;
900 make_search_status (&pi, sc);
901 sc->client_info = sc->h->upcb (sc->h->upcb_cls,
907 * Free the given search result.
909 * @param cls the global FS handle
910 * @param key the key for the search result (unused)
911 * @param value the search result to free
915 search_result_free (void *cls,
916 const GNUNET_HashCode * key,
919 struct GNUNET_FS_SearchContext *sc = cls;
920 struct GNUNET_FS_Handle *h = sc->h;
921 struct SearchResult *sr = value;
922 struct GNUNET_FS_ProgressInfo pi;
924 pi.status = GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED;
925 make_search_status (&pi, sc);
926 pi.value.search.specifics.result_stopped.cctx = sr->client_info;
927 pi.value.search.specifics.result_stopped.meta = sr->meta;
928 pi.value.search.specifics.result_stopped.uri = sr->uri;
929 sr->client_info = h->upcb (h->upcb_cls,
931 GNUNET_break (NULL == sr->client_info);
933 GNUNET_FS_uri_destroy (sr->uri);
934 GNUNET_CONTAINER_meta_data_destroy (sr->meta);
935 if (sr->probe_ctx != NULL)
937 GNUNET_FS_download_stop (sr->probe_ctx, GNUNET_YES);
939 /* FIXME: trigger starting of new
940 probes here!? Maybe not -- could
941 cause new probes to be immediately
944 if (sr->probe_cancel_task != GNUNET_SCHEDULER_NO_TASK)
946 GNUNET_SCHEDULER_cancel (h->sched,
947 sr->probe_cancel_task);
955 * Stop search for content.
957 * @param sc context for the search that should be stopped
960 GNUNET_FS_search_stop (struct GNUNET_FS_SearchContext *sc)
962 struct GNUNET_FS_ProgressInfo pi;
964 struct GNUNET_FS_SearchContext *parent;
966 // FIXME: make un-persistent!
967 if (NULL != (parent = sc->parent))
969 GNUNET_CONTAINER_DLL_remove (parent->child_head,
974 while (NULL != sc->child_head)
975 GNUNET_FS_search_stop (sc->child_head);
976 GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map,
979 pi.status = GNUNET_FS_STATUS_SEARCH_STOPPED;
980 make_search_status (&pi, sc);
981 sc->client_info = sc->h->upcb (sc->h->upcb_cls,
983 GNUNET_break (NULL == sc->client_info);
984 if (sc->task != GNUNET_SCHEDULER_NO_TASK)
985 GNUNET_SCHEDULER_cancel (sc->h->sched,
987 if (NULL != sc->client)
988 GNUNET_CLIENT_disconnect (sc->client, GNUNET_NO);
989 GNUNET_CONTAINER_multihashmap_destroy (sc->master_result_map);
990 if (sc->requests != NULL)
992 GNUNET_assert (GNUNET_FS_uri_test_ksk (sc->uri));
993 for (i=0;i<sc->uri->data.ksk.keywordCount;i++)
994 GNUNET_CONTAINER_multihashmap_destroy (sc->requests[i].results);
996 GNUNET_free_non_null (sc->requests);
997 GNUNET_FS_uri_destroy (sc->uri);
1001 /* end of fs_search.c */