diff options
author | Christian Grothoff <christian@grothoff.org> | 2009-09-04 08:12:54 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2009-09-04 08:12:54 +0000 |
commit | f8bfdee4d3a12ccc63b4f340b3032ae3b0ee5fd1 (patch) | |
tree | e7f08426d4d44a4e68d974f51155c739d9127ccb /src | |
parent | 0624f202f56751abbccb16f08031c03b20a921a9 (diff) | |
download | gnunet-f8bfdee4d3a12ccc63b4f340b3032ae3b0ee5fd1.tar.gz gnunet-f8bfdee4d3a12ccc63b4f340b3032ae3b0ee5fd1.zip |
towards search
Diffstat (limited to 'src')
-rw-r--r-- | src/fs/fs.h | 160 | ||||
-rw-r--r-- | src/fs/fs_search.c | 984 | ||||
-rw-r--r-- | src/fs/fs_unindex.c | 98 | ||||
-rw-r--r-- | src/include/gnunet_protocols.h | 10 |
4 files changed, 701 insertions, 551 deletions
diff --git a/src/fs/fs.h b/src/fs/fs.h index 7df395e86..6e793bf8d 100644 --- a/src/fs/fs.h +++ b/src/fs/fs.h | |||
@@ -583,10 +583,70 @@ struct GNUNET_FS_UnindexContext | |||
583 | 583 | ||
584 | 584 | ||
585 | /** | 585 | /** |
586 | * Information we keep for each keyword in | ||
587 | * a keyword search. | ||
588 | */ | ||
589 | struct SearchRequestEntry | ||
590 | { | ||
591 | /** | ||
592 | * Hash of the original keyword, also known as the | ||
593 | * key (for decrypting the KBlock). | ||
594 | */ | ||
595 | GNUNET_HashCode key; | ||
596 | |||
597 | /** | ||
598 | * Hash of the public key, also known as the query. | ||
599 | */ | ||
600 | GNUNET_HashCode query; | ||
601 | }; | ||
602 | |||
603 | |||
604 | /** | ||
586 | * Handle for controlling a search. | 605 | * Handle for controlling a search. |
587 | */ | 606 | */ |
588 | struct GNUNET_FS_SearchContext | 607 | struct GNUNET_FS_SearchContext |
589 | { | 608 | { |
609 | /** | ||
610 | * Handle to the global FS context. | ||
611 | */ | ||
612 | struct GNUNET_FS_Handle *h; | ||
613 | |||
614 | /** | ||
615 | * List of keywords that we're looking for. | ||
616 | */ | ||
617 | struct GNUNET_FS_Uri *uri; | ||
618 | |||
619 | /** | ||
620 | * Connection to the FS service. | ||
621 | */ | ||
622 | struct GNUNET_CLIENT_Connection *client; | ||
623 | |||
624 | /** | ||
625 | * Per-keyword information for a keyword search. | ||
626 | */ | ||
627 | struct SearchRequestEntry *requests; | ||
628 | |||
629 | /** | ||
630 | * When did we start? | ||
631 | */ | ||
632 | struct GNUNET_TIME_Absolute start_time; | ||
633 | |||
634 | /** | ||
635 | * ID of a task that is using this struct | ||
636 | * and that must be cancelled when the search | ||
637 | * is being stopped (if not GNUNET_SCHEDULER_NO_TASK). | ||
638 | * Used for the task that adds some artificial | ||
639 | * delay when trying to reconnect to the FS | ||
640 | * service. | ||
641 | */ | ||
642 | GNUNET_SCHEDULER_TaskIdentifier task; | ||
643 | |||
644 | /** | ||
645 | * Anonymity level for the search. | ||
646 | */ | ||
647 | unsigned int anonymity; | ||
648 | |||
649 | |||
590 | }; | 650 | }; |
591 | 651 | ||
592 | 652 | ||
@@ -630,7 +690,7 @@ struct OnDemandBlock | |||
630 | * At which offset should we be able to find | 690 | * At which offset should we be able to find |
631 | * this on-demand encoded block? | 691 | * this on-demand encoded block? |
632 | */ | 692 | */ |
633 | uint64_t offset; | 693 | uint64_t offset GNUNET_PACKED; |
634 | 694 | ||
635 | }; | 695 | }; |
636 | 696 | ||
@@ -733,7 +793,7 @@ struct IndexStartMessage | |||
733 | * OS does not support this, in which case the service must do a | 793 | * OS does not support this, in which case the service must do a |
734 | * full hash recomputation. | 794 | * full hash recomputation. |
735 | */ | 795 | */ |
736 | uint32_t device; | 796 | uint32_t device GNUNET_PACKED; |
737 | 797 | ||
738 | /** | 798 | /** |
739 | * Inode of the file on the given device, as seen by the client | 799 | * Inode of the file on the given device, as seen by the client |
@@ -741,7 +801,7 @@ struct IndexStartMessage | |||
741 | * support this, in which case the service must do a full hash | 801 | * support this, in which case the service must do a full hash |
742 | * recomputation. | 802 | * recomputation. |
743 | */ | 803 | */ |
744 | uint64_t inode; | 804 | uint64_t inode GNUNET_PACKED; |
745 | 805 | ||
746 | /** | 806 | /** |
747 | * Hash of the file that we would like to index. | 807 | * Hash of the file that we would like to index. |
@@ -768,6 +828,11 @@ struct IndexInfoMessage | |||
768 | struct GNUNET_MessageHeader header; | 828 | struct GNUNET_MessageHeader header; |
769 | 829 | ||
770 | /** | 830 | /** |
831 | * Always zero. | ||
832 | */ | ||
833 | uint32_t reserved GNUNET_PACKED; | ||
834 | |||
835 | /** | ||
771 | * Hash of the indexed file. | 836 | * Hash of the indexed file. |
772 | */ | 837 | */ |
773 | GNUNET_HashCode file_id; | 838 | GNUNET_HashCode file_id; |
@@ -800,7 +865,7 @@ struct UnindexMessage | |||
800 | /** | 865 | /** |
801 | * Always zero. | 866 | * Always zero. |
802 | */ | 867 | */ |
803 | uint32_t reserved; | 868 | uint32_t reserved GNUNET_PACKED; |
804 | 869 | ||
805 | /** | 870 | /** |
806 | * Hash of the file that we will unindex. | 871 | * Hash of the file that we will unindex. |
@@ -810,6 +875,93 @@ struct UnindexMessage | |||
810 | }; | 875 | }; |
811 | 876 | ||
812 | 877 | ||
878 | /** | ||
879 | * Message sent from a GNUnet (fs) search | ||
880 | * activity to the gnunet-fs-service to | ||
881 | * start a search. | ||
882 | */ | ||
883 | struct SearchMessage | ||
884 | { | ||
885 | |||
886 | /** | ||
887 | * Message type will be | ||
888 | * GNUNET_MESSAGE_TYPE_FS_START_SEARCH. | ||
889 | */ | ||
890 | struct GNUNET_MessageHeader header; | ||
891 | |||
892 | /** | ||
893 | * Should be zero. | ||
894 | */ | ||
895 | int32_t reserved GNUNET_PACKED; | ||
896 | |||
897 | /** | ||
898 | * Type of the content that we're looking for. | ||
899 | * 0 for any. | ||
900 | */ | ||
901 | uint32_t type GNUNET_PACKED; | ||
902 | |||
903 | /** | ||
904 | * Desired anonymity level, big-endian. | ||
905 | */ | ||
906 | uint32_t anonymity_level GNUNET_PACKED; | ||
907 | |||
908 | /** | ||
909 | * If the request is for a DBLOCK or IBLOCK, this is the identity of | ||
910 | * the peer that is known to have a response. Set to all-zeros if | ||
911 | * such a target is not known (note that even if OUR anonymity | ||
912 | * level is >0 we may happen to know the responder's identity; | ||
913 | * nevertheless, we should probably not use it for a DHT-lookup | ||
914 | * or similar blunt actions in order to avoid exposing ourselves). | ||
915 | * <p> | ||
916 | * If the request is for an SBLOCK, this is the identity of the | ||
917 | * pseudonym to which the SBLOCK belongs. | ||
918 | * <p> | ||
919 | * If the request is for a KBLOCK, "target" must be all zeros. | ||
920 | */ | ||
921 | GNUNET_HashCode target; | ||
922 | |||
923 | /** | ||
924 | * Hash of the keyword (aka query) for KBLOCKs; Hash of | ||
925 | * the CHK-encoded block for DBLOCKS and IBLOCKS (aka query) | ||
926 | * and hash of the identifier XORed with the target for | ||
927 | * SBLOCKS (aka query). | ||
928 | */ | ||
929 | GNUNET_HashCode query; | ||
930 | |||
931 | }; | ||
932 | |||
933 | |||
934 | /** | ||
935 | * Response from FS service with a result for | ||
936 | * a previous FS search. Note that queries | ||
937 | * for DBLOCKS and IBLOCKS that have received | ||
938 | * a single response are considered done. | ||
939 | */ | ||
940 | struct ContentMessage | ||
941 | { | ||
942 | |||
943 | /** | ||
944 | * Message type will be | ||
945 | * GNUNET_MESSAGE_TYPE_FS_CONTENT. | ||
946 | */ | ||
947 | struct GNUNET_MessageHeader header; | ||
948 | |||
949 | /** | ||
950 | * Type of the content that was found, | ||
951 | * should never be 0. | ||
952 | */ | ||
953 | uint32_t type GNUNET_PACKED; | ||
954 | |||
955 | /** | ||
956 | * When will this result expire? | ||
957 | */ | ||
958 | struct GNUNET_TIME_AbsoluteNBO expiration; | ||
959 | |||
960 | /* followed by the actual block of data */ | ||
961 | |||
962 | }; | ||
963 | |||
964 | |||
813 | 965 | ||
814 | #endif | 966 | #endif |
815 | 967 | ||
diff --git a/src/fs/fs_search.c b/src/fs/fs_search.c index 51d1fbc1f..e855a4d30 100644 --- a/src/fs/fs_search.c +++ b/src/fs/fs_search.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008 Christian Grothoff (and other contributing authors) | 3 | (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009 Christian Grothoff (and other contributing authors) |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published |
@@ -22,604 +22,592 @@ | |||
22 | * @file fs/fs_search.c | 22 | * @file fs/fs_search.c |
23 | * @brief Helper functions for searching. | 23 | * @brief Helper functions for searching. |
24 | * @author Christian Grothoff | 24 | * @author Christian Grothoff |
25 | * | ||
26 | * TODO: | ||
27 | * - aggregate and process results (FSUI-style) | ||
28 | * - call progress callbacks | ||
29 | * - make operations persistent (can wait) | ||
30 | * - add support for pushing "already seen" information | ||
31 | * to FS service for bloomfilter (can wait) | ||
25 | */ | 32 | */ |
26 | 33 | ||
27 | #include "platform.h" | 34 | #include "platform.h" |
35 | #include "gnunet_constants.h" | ||
28 | #include "gnunet_fs_service.h" | 36 | #include "gnunet_fs_service.h" |
37 | #include "gnunet_protocols.h" | ||
29 | #include "fs.h" | 38 | #include "fs.h" |
30 | 39 | ||
31 | #define DEBUG_SEARCH GNUNET_YES | 40 | #define DEBUG_SEARCH GNUNET_YES |
32 | 41 | ||
33 | 42 | ||
34 | /** | 43 | /** |
35 | * Start search for content. | 44 | * We have received a KSK result. Check |
45 | * how it fits in with the overall query | ||
46 | * and notify the client accordingly. | ||
36 | * | 47 | * |
37 | * @param h handle to the file sharing subsystem | 48 | * @param sc context for the overall query |
38 | * @param uri specifies the search parameters; can be | 49 | * @param ent entry for the specific keyword |
39 | * a KSK URI or an SKS URI. | 50 | * @param uri the URI that was found |
40 | * @param anonymity desired level of anonymity | 51 | * @param meta metadata associated with the URI |
41 | * @return context that can be used to control the search | 52 | * under the "ent" keyword |
42 | */ | 53 | */ |
43 | struct GNUNET_FS_SearchContext * | 54 | static void |
44 | GNUNET_FS_search_start (struct GNUNET_FS_Handle *h, | 55 | process_ksk_result (struct GNUNET_FS_SearchContext *sc, |
45 | const struct GNUNET_FS_Uri *uri, | 56 | struct SearchRequestEntry *ent, |
46 | unsigned int anonymity) | 57 | const struct GNUNET_FS_Uri *uri, |
58 | const struct GNUNET_CONTAINER_MetaData *meta) | ||
47 | { | 59 | { |
48 | return NULL; | 60 | // FIXME: check if new |
61 | // FIXME: check if mandatory satisfied | ||
62 | // FIXME: notify client! | ||
49 | } | 63 | } |
50 | 64 | ||
51 | 65 | ||
52 | /** | 66 | /** |
53 | * Pause search. | 67 | * We have received an SKS result. Start |
68 | * searching for updates and notify the | ||
69 | * client if it is a new result. | ||
54 | * | 70 | * |
55 | * @param sc context for the search that should be paused | 71 | * @param sc context for the overall query |
56 | */ | 72 | * @param id_update identifier for updates, NULL for none |
57 | void | 73 | * @param uri the URI that was found |
58 | GNUNET_FS_search_pause (struct GNUNET_FS_SearchContext *sc) | 74 | * @param meta metadata associated with the URI |
75 | */ | ||
76 | static void | ||
77 | process_sks_result (struct GNUNET_FS_SearchContext *sc, | ||
78 | const char *id_update, | ||
79 | const struct GNUNET_FS_Uri *uri, | ||
80 | const struct GNUNET_CONTAINER_MetaData *meta) | ||
59 | { | 81 | { |
82 | // FIXME: check if new | ||
83 | // FIXME: notify client | ||
84 | |||
85 | if (strlen (id_update) > 0) | ||
86 | { | ||
87 | // FIXME: search for updates! | ||
88 | #if 0 | ||
89 | updateURI.type = sks; | ||
90 | GNUNET_hash (&sb->subspace, | ||
91 | sizeof (GNUNET_RSA_PublicKey), | ||
92 | &updateURI.data.sks.namespace); | ||
93 | updateURI.data.sks.identifier = GNUNET_strdup (id); | ||
94 | add_search_for_uri (&updateURI, sqc); | ||
95 | #endif | ||
96 | } | ||
60 | } | 97 | } |
61 | 98 | ||
99 | |||
62 | /** | 100 | /** |
63 | * Continue paused search. | 101 | * Process a keyword-search result. |
64 | * | 102 | * |
65 | * @param sc context for the search that should be resumed | 103 | * @param sc our search context |
104 | * @param kb the kblock | ||
105 | * @param size size of kb | ||
66 | */ | 106 | */ |
67 | void | 107 | static void |
68 | GNUNET_FS_search_continue (struct GNUNET_FS_SearchContext *sc) | 108 | process_kblock (struct GNUNET_FS_SearchContext *sc, |
109 | const struct KBlock *kb, | ||
110 | size_t size) | ||
69 | { | 111 | { |
112 | unsigned int i; | ||
113 | size_t j; | ||
114 | GNUNET_HashCode q; | ||
115 | char pt[size - sizeof (struct KBlock)]; | ||
116 | struct GNUNET_CRYPTO_AesSessionKey skey; | ||
117 | struct GNUNET_CRYPTO_AesInitializationVector iv; | ||
118 | const char *eos; | ||
119 | struct GNUNET_CONTAINER_MetaData *meta; | ||
120 | struct GNUNET_FS_Uri *uri; | ||
121 | char *emsg; | ||
122 | |||
123 | GNUNET_CRYPTO_hash (&kb->keyspace, | ||
124 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), | ||
125 | &q); | ||
126 | /* find key */ | ||
127 | for (i=0;i<sc->uri->data.ksk.keywordCount;i++) | ||
128 | if (0 == memcmp (&q, | ||
129 | &sc->requests[i].query, | ||
130 | sizeof (GNUNET_HashCode))) | ||
131 | break; | ||
132 | if (i == sc->uri->data.ksk.keywordCount) | ||
133 | { | ||
134 | /* oops, does not match any of our keywords!? */ | ||
135 | GNUNET_break (0); | ||
136 | return; | ||
137 | } | ||
138 | /* decrypt */ | ||
139 | GNUNET_CRYPTO_hash_to_aes_key (&sc->requests[i].key, &skey, &iv); | ||
140 | GNUNET_CRYPTO_aes_encrypt (&kb[1], | ||
141 | size - sizeof (struct KBlock), | ||
142 | &skey, | ||
143 | &iv, | ||
144 | pt); | ||
145 | /* parse */ | ||
146 | eos = memchr (pt, 0, sizeof (pt)); | ||
147 | if (NULL == eos) | ||
148 | { | ||
149 | GNUNET_break_op (0); | ||
150 | return; | ||
151 | } | ||
152 | j = eos - pt + 1; | ||
153 | meta = GNUNET_CONTAINER_meta_data_deserialize (&pt[j], | ||
154 | sizeof (pt) - j); | ||
155 | if (meta == NULL) | ||
156 | { | ||
157 | GNUNET_break_op (0); /* kblock malformed */ | ||
158 | return; | ||
159 | } | ||
160 | uri = GNUNET_FS_uri_parse (pt, &emsg); | ||
161 | if (uri == NULL) | ||
162 | { | ||
163 | GNUNET_break_op (0); /* kblock malformed */ | ||
164 | GNUNET_free_non_null (emsg); | ||
165 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
166 | return; | ||
167 | } | ||
168 | /* process */ | ||
169 | process_ksk_result (sc, &sc->requests[i], uri, meta); | ||
170 | |||
171 | /* clean up */ | ||
172 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
173 | GNUNET_FS_uri_destroy (uri); | ||
70 | } | 174 | } |
71 | 175 | ||
72 | 176 | ||
73 | /** | 177 | /** |
74 | * Stop search for content. | 178 | * Process a namespace-search result. |
75 | * | 179 | * |
76 | * @param sc context for the search that should be stopped | 180 | * @param sc our search context |
181 | * @param sb the sblock | ||
182 | * @param size size of sb | ||
77 | */ | 183 | */ |
78 | void | 184 | static void |
79 | GNUNET_FS_search_stop (struct GNUNET_FS_SearchContext *sc) | 185 | process_sblock (struct GNUNET_FS_SearchContext *sc, |
186 | const struct SBlock *sb, | ||
187 | size_t size) | ||
80 | { | 188 | { |
189 | size_t len = size - sizeof (struct SBlock); | ||
190 | char pt[len]; | ||
191 | struct GNUNET_CRYPTO_AesSessionKey skey; | ||
192 | struct GNUNET_CRYPTO_AesInitializationVector iv; | ||
193 | struct GNUNET_FS_Uri *uri; | ||
194 | struct GNUNET_CONTAINER_MetaData *meta; | ||
195 | const char *id; | ||
196 | const char *uris; | ||
197 | size_t off; | ||
198 | char *emsg; | ||
199 | GNUNET_HashCode key; | ||
200 | char *identifier; | ||
201 | |||
202 | /* decrypt */ | ||
203 | identifier = sc->uri->data.sks.identifier; | ||
204 | GNUNET_CRYPTO_hash (identifier, | ||
205 | strlen (identifier), | ||
206 | &key); | ||
207 | GNUNET_CRYPTO_hash_to_aes_key (&key, &skey, &iv); | ||
208 | GNUNET_CRYPTO_aes_encrypt (&sb[1], | ||
209 | len, | ||
210 | &skey, | ||
211 | &iv, | ||
212 | pt); | ||
213 | /* parse */ | ||
214 | off = GNUNET_STRINGS_buffer_tokenize (pt, | ||
215 | len, | ||
216 | 2, | ||
217 | &id, | ||
218 | &uris); | ||
219 | if (off == 0) | ||
220 | { | ||
221 | GNUNET_break_op (0); /* sblock malformed */ | ||
222 | return; | ||
223 | } | ||
224 | meta = GNUNET_CONTAINER_meta_data_deserialize (&pt[off], | ||
225 | len - off); | ||
226 | if (meta == NULL) | ||
227 | { | ||
228 | GNUNET_break_op (0); /* sblock malformed */ | ||
229 | return; | ||
230 | } | ||
231 | uri = GNUNET_FS_uri_parse (uris, &emsg); | ||
232 | if (uri == NULL) | ||
233 | { | ||
234 | GNUNET_break_op (0); /* sblock malformed */ | ||
235 | GNUNET_free_non_null (emsg); | ||
236 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
237 | return; | ||
238 | } | ||
239 | /* process */ | ||
240 | process_sks_result (sc, id, uri, meta); | ||
241 | /* clean up */ | ||
242 | GNUNET_FS_uri_destroy (uri); | ||
243 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
81 | } | 244 | } |
82 | 245 | ||
83 | 246 | ||
84 | |||
85 | |||
86 | #if 0 | ||
87 | |||
88 | /** | 247 | /** |
89 | * Context for an individual search. Followed | 248 | * Process a search result. |
90 | * by keyCount keys of type GNUNET_HashCode. | 249 | * |
250 | * @param sc our search context | ||
251 | * @param type type of the result | ||
252 | * @param expiration when it will expire | ||
253 | * @param data the (encrypted) response | ||
254 | * @param size size of data | ||
91 | */ | 255 | */ |
92 | struct PendingSearch | 256 | static void |
257 | process_result (struct GNUNET_FS_SearchContext *sc, | ||
258 | uint32_t type, | ||
259 | struct GNUNET_TIME_Absolute expiration, | ||
260 | const void *data, | ||
261 | size_t size) | ||
93 | { | 262 | { |
94 | struct PendingSearch *next; | 263 | if (GNUNET_TIME_absolute_get_duration (expiration).value > 0) |
95 | 264 | return; /* result expired */ | |
96 | struct GNUNET_ECRS_SearchContext *context; | 265 | switch (type) |
97 | 266 | { | |
98 | /** | 267 | case GNUNET_DATASTORE_BLOCKTYPE_KBLOCK: |
99 | * The key (for decryption) | 268 | if (! GNUNET_FS_uri_test_ksk (sc->uri)) |
100 | */ | 269 | { |
101 | GNUNET_HashCode decryptKey; | 270 | GNUNET_break (0); |
102 | 271 | return; | |
103 | unsigned int keyCount; | 272 | } |
104 | 273 | if (sizeof (struct KBlock) > size) | |
105 | /** | 274 | { |
106 | * What type of query is it? | 275 | GNUNET_break_op (0); |
107 | */ | 276 | return; |
108 | unsigned int type; | 277 | } |
278 | process_kblock (sc, data, size); | ||
279 | break; | ||
280 | case GNUNET_DATASTORE_BLOCKTYPE_SBLOCK: | ||
281 | if (! GNUNET_FS_uri_test_ksk (sc->uri)) | ||
282 | { | ||
283 | GNUNET_break (0); | ||
284 | return; | ||
285 | } | ||
286 | if (sizeof (struct SBlock) > size) | ||
287 | { | ||
288 | GNUNET_break_op (0); | ||
289 | return; | ||
290 | } | ||
291 | process_sblock (sc, data, size); | ||
292 | break; | ||
293 | case GNUNET_DATASTORE_BLOCKTYPE_ANY: | ||
294 | case GNUNET_DATASTORE_BLOCKTYPE_DBLOCK: | ||
295 | case GNUNET_DATASTORE_BLOCKTYPE_ONDEMAND: | ||
296 | case GNUNET_DATASTORE_BLOCKTYPE_IBLOCK: | ||
297 | GNUNET_break (0); | ||
298 | break; | ||
299 | default: | ||
300 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
301 | _("Got result with unknown block type `%d', ignoring"), | ||
302 | type); | ||
303 | break; | ||
304 | } | ||
305 | } | ||
109 | 306 | ||
110 | }; | ||
111 | 307 | ||
112 | /** | 308 | /** |
113 | * Context for search operation. | 309 | * Shutdown any existing connection to the FS |
310 | * service and try to establish a fresh one | ||
311 | * (and then re-transmit our search request). | ||
312 | * | ||
313 | * @param sc the search to reconnec | ||
114 | */ | 314 | */ |
115 | struct GNUNET_ECRS_SearchContext | 315 | static void |
116 | { | 316 | try_reconnect (struct GNUNET_FS_SearchContext *sc); |
117 | /** | ||
118 | * Time when the cron-job was first started. | ||
119 | */ | ||
120 | GNUNET_CronTime start; | ||
121 | |||
122 | /** | ||
123 | * What is the global timeout? | ||
124 | */ | ||
125 | GNUNET_CronTime timeout; | ||
126 | |||
127 | /** | ||
128 | * Search context | ||
129 | */ | ||
130 | struct GNUNET_FS_SearchContext *sctx; | ||
131 | |||
132 | /** | ||
133 | * Active searches. | ||
134 | */ | ||
135 | struct PendingSearch *queries; | ||
136 | |||
137 | GNUNET_ECRS_SearchResultProcessor spcb; | ||
138 | |||
139 | void *spcbClosure; | ||
140 | |||
141 | struct GNUNET_GE_Context *ectx; | ||
142 | |||
143 | struct GNUNET_GC_Configuration *cfg; | ||
144 | |||
145 | int aborted; | ||
146 | |||
147 | int my_sctx; | ||
148 | 317 | ||
149 | unsigned int anonymityLevel; | ||
150 | |||
151 | }; | ||
152 | |||
153 | static int | ||
154 | receive_response_callback (const GNUNET_HashCode * key, | ||
155 | const GNUNET_DatastoreValue * value, | ||
156 | void *cls, unsigned long long uid); | ||
157 | |||
158 | /** | ||
159 | * Add a query to the SQC. | ||
160 | */ | ||
161 | static void | ||
162 | add_search (unsigned int type, | ||
163 | unsigned int keyCount, | ||
164 | const GNUNET_HashCode * keys, | ||
165 | const GNUNET_HashCode * dkey, | ||
166 | struct GNUNET_ECRS_SearchContext *sqc) | ||
167 | { | ||
168 | struct PendingSearch *ps; | ||
169 | |||
170 | ps = | ||
171 | GNUNET_malloc (sizeof (struct PendingSearch) + | ||
172 | sizeof (GNUNET_HashCode) * keyCount); | ||
173 | ps->type = type; | ||
174 | ps->keyCount = keyCount; | ||
175 | memcpy (&ps[1], keys, sizeof (GNUNET_HashCode) * keyCount); | ||
176 | ps->decryptKey = *dkey; | ||
177 | ps->context = sqc; | ||
178 | ps->next = sqc->queries; | ||
179 | sqc->queries = ps; | ||
180 | GNUNET_FS_start_search (sqc->sctx, | ||
181 | NULL, | ||
182 | type, | ||
183 | keyCount, | ||
184 | keys, | ||
185 | sqc->anonymityLevel, | ||
186 | &receive_response_callback, ps); | ||
187 | } | ||
188 | 318 | ||
189 | /** | 319 | /** |
190 | * Add the query that corresponds to the given URI | 320 | * Type of a function to call when we receive a message |
191 | * to the SQC. | 321 | * from the service. |
322 | * | ||
323 | * @param cls closure | ||
324 | * @param msg message received, NULL on timeout or fatal error | ||
192 | */ | 325 | */ |
193 | static void | 326 | static void |
194 | add_search_for_uri (const struct GNUNET_ECRS_URI *uri, | 327 | receive_results (void *cls, |
195 | struct GNUNET_ECRS_SearchContext *sqc) | 328 | const struct GNUNET_MessageHeader * msg) |
196 | { | 329 | { |
197 | struct GNUNET_GE_Context *ectx = sqc->ectx; | 330 | struct GNUNET_FS_SearchContext *sc = cls; |
331 | const struct ContentMessage *cm; | ||
332 | uint16_t msize; | ||
198 | 333 | ||
199 | switch (uri->type) | 334 | if ( (NULL == msg) || |
335 | (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_FS_CONTENT) || | ||
336 | (ntohs (msg->size) <= sizeof (struct ContentMessage)) ) | ||
200 | { | 337 | { |
201 | case chk: | 338 | try_reconnect (sc); |
202 | GNUNET_GE_LOG (ectx, | 339 | return; |
203 | GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_USER, | ||
204 | _("CHK URI not allowed for search.\n")); | ||
205 | break; | ||
206 | case sks: | ||
207 | { | ||
208 | GNUNET_HashCode keys[2]; | ||
209 | GNUNET_HashCode hk; /* hk = GNUNET_hash(identifier) */ | ||
210 | GNUNET_HashCode hk2; /* hk2 = GNUNET_hash(hk) */ | ||
211 | |||
212 | GNUNET_hash (uri->data.sks.identifier, | ||
213 | strlen (uri->data.sks.identifier), &hk); | ||
214 | GNUNET_hash (&hk, sizeof (GNUNET_HashCode), &hk2); | ||
215 | /* compute routing key keys[0] = H(key) ^ namespace */ | ||
216 | GNUNET_hash_xor (&hk2, &uri->data.sks.namespace, &keys[0]); | ||
217 | keys[1] = uri->data.sks.namespace; | ||
218 | add_search (GNUNET_ECRS_BLOCKTYPE_SIGNED, 2, &keys[0], &hk, sqc); | ||
219 | break; | ||
220 | } | ||
221 | case ksk: | ||
222 | { | ||
223 | GNUNET_HashCode hc; | ||
224 | GNUNET_HashCode query; | ||
225 | struct GNUNET_RSA_PrivateKey *pk; | ||
226 | GNUNET_RSA_PublicKey pub; | ||
227 | int i; | ||
228 | const char *keyword; | ||
229 | |||
230 | #if DEBUG_SEARCH | ||
231 | GNUNET_GE_LOG (ectx, | ||
232 | GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER, | ||
233 | "Computing queries (this may take a while).\n"); | ||
234 | #endif | ||
235 | for (i = 0; i < uri->data.ksk.keywordCount; i++) | ||
236 | { | ||
237 | keyword = uri->data.ksk.keywords[i]; | ||
238 | /* first character of the keyword is | ||
239 | "+" or " " to indicate mandatory or | ||
240 | not -- ignore for hashing! */ | ||
241 | GNUNET_hash (&keyword[1], strlen (&keyword[1]), &hc); | ||
242 | pk = GNUNET_RSA_create_key_from_hash (&hc); | ||
243 | GNUNET_RSA_get_public_key (pk, &pub); | ||
244 | GNUNET_hash (&pub, sizeof (GNUNET_RSA_PublicKey), &query); | ||
245 | add_search (GNUNET_ECRS_BLOCKTYPE_ANY, /* GNUNET_ECRS_BLOCKTYPE_KEYWORD, GNUNET_ECRS_BLOCKTYPE_NAMESPACE or GNUNET_ECRS_BLOCKTYPE_KEYWORD_FOR_NAMESPACE ok */ | ||
246 | 1, &query, &hc, sqc); | ||
247 | GNUNET_RSA_free_key (pk); | ||
248 | } | ||
249 | #if DEBUG_SEARCH | ||
250 | GNUNET_GE_LOG (ectx, | ||
251 | GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER, | ||
252 | "Queries ready.\n"); | ||
253 | #endif | ||
254 | break; | ||
255 | } | ||
256 | case loc: | ||
257 | GNUNET_GE_LOG (ectx, | ||
258 | GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_USER, | ||
259 | _("LOC URI not allowed for search.\n")); | ||
260 | break; | ||
261 | default: | ||
262 | GNUNET_GE_BREAK (ectx, 0); | ||
263 | /* unknown URI type */ | ||
264 | break; | ||
265 | } | 340 | } |
341 | msize = ntohs (msg->size); | ||
342 | cm = (const struct ContentMessage*) msg; | ||
343 | process_result (sc, | ||
344 | ntohl (cm->type), | ||
345 | GNUNET_TIME_absolute_ntoh (cm->expiration), | ||
346 | &cm[1], | ||
347 | msize - sizeof (struct ContentMessage)); | ||
348 | /* continue receiving */ | ||
349 | GNUNET_CLIENT_receive (sc->client, | ||
350 | &receive_results, | ||
351 | sc, | ||
352 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
266 | } | 353 | } |
267 | 354 | ||
355 | |||
268 | /** | 356 | /** |
269 | * We found an GNUNET_EC_SBlock. Decode the meta-data and call | 357 | * We're ready to transmit the search request to the |
270 | * the callback of the SQC with the root-URI for the namespace, | 358 | * file-sharing service. Do it. |
271 | * together with the namespace advertisement. Also, if this is | 359 | * |
272 | * a result with updates, automatically start the search for | 360 | * @param cls closure |
273 | * updates. | 361 | * @param size number of bytes available in buf |
362 | * @param buf where the callee should write the message | ||
363 | * @return number of bytes written to buf | ||
274 | */ | 364 | */ |
275 | static int | 365 | static size_t |
276 | process_sblock_result (const GNUNET_EC_SBlock * sb, | 366 | transmit_search_request (void *cls, |
277 | const GNUNET_HashCode * key, | 367 | size_t size, |
278 | unsigned int size, | 368 | void *buf) |
279 | struct GNUNET_ECRS_SearchContext *sqc) | ||
280 | { | 369 | { |
281 | static GNUNET_HashCode allZeros; | 370 | struct GNUNET_FS_SearchContext *sc = cls; |
282 | struct GNUNET_GE_Context *ectx = sqc->ectx; | 371 | size_t msize; |
283 | GNUNET_ECRS_FileInfo fi; | 372 | struct SearchMessage *sm; |
284 | URI updateURI; | 373 | unsigned int i; |
285 | int ret; | 374 | const char *keyword; |
286 | const char *id; | 375 | const char *identifier; |
287 | const char *uris; | 376 | GNUNET_HashCode idh; |
288 | unsigned int len; | 377 | GNUNET_HashCode hc; |
289 | unsigned int off; | 378 | struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub; |
290 | int isRoot; | 379 | struct GNUNET_CRYPTO_RsaPrivateKey *pk; |
291 | 380 | ||
292 | len = size - sizeof (GNUNET_EC_SBlock); | 381 | if (NULL == buf) |
293 | off = GNUNET_string_buffer_tokenize ((const char *) &sb[1], | ||
294 | len, 2, &id, &uris); | ||
295 | if (off == 0) | ||
296 | { | 382 | { |
297 | GNUNET_GE_BREAK_OP (ectx, 0); /* sblock malformed */ | 383 | try_reconnect (sc); |
298 | return GNUNET_SYSERR; | 384 | return 0; |
299 | } | 385 | } |
300 | fi.meta = GNUNET_meta_data_deserialize (ectx, &id[off], len - off); | 386 | if (GNUNET_FS_uri_test_ksk (sc->uri)) |
301 | if (fi.meta == NULL) | ||
302 | { | 387 | { |
303 | GNUNET_GE_BREAK_OP (ectx, 0); /* sblock malformed */ | 388 | msize = sizeof (struct SearchMessage) * sc->uri->data.ksk.keywordCount; |
304 | return GNUNET_SYSERR; | 389 | GNUNET_assert (size >= msize); |
305 | } | 390 | sm = buf; |
306 | isRoot = 0 == memcmp (&sb->identifier, &allZeros, sizeof (GNUNET_HashCode)); | 391 | memset (sm, 0, msize); |
307 | fi.uri = GNUNET_ECRS_string_to_uri (ectx, uris); | 392 | sc->requests = GNUNET_malloc (sizeof (struct SearchRequestEntry) * |
308 | if ((isRoot) && (fi.uri == NULL)) | 393 | sc->uri->data.ksk.keywordCount); |
309 | { | 394 | for (i=0;i<sc->uri->data.ksk.keywordCount;i++) |
310 | fi.uri = GNUNET_malloc (sizeof (URI)); | 395 | { |
311 | fi.uri->type = sks; | 396 | sm[i].header.size = htons (sizeof (struct SearchMessage)); |
312 | GNUNET_hash (&sb->subspace, | 397 | sm[i].header.type = htons (GNUNET_MESSAGE_TYPE_FS_START_SEARCH); |
313 | sizeof (GNUNET_RSA_PublicKey), | 398 | sm[i].anonymity_level = htonl (sc->anonymity); |
314 | &fi.uri->data.sks.namespace); | 399 | keyword = &sc->uri->data.ksk.keywords[i][1]; |
315 | fi.uri->data.sks.identifier = GNUNET_strdup (id); | 400 | |
316 | } | 401 | GNUNET_CRYPTO_hash (keyword, strlen (keyword), &hc); |
317 | if (fi.uri == NULL) | 402 | pk = GNUNET_CRYPTO_rsa_key_create_from_hash (&hc); |
318 | { | 403 | GNUNET_CRYPTO_rsa_key_get_public (pk, &pub); |
319 | GNUNET_GE_BREAK_OP (ectx, 0); /* sblock malformed */ | 404 | GNUNET_CRYPTO_rsa_key_free (pk); |
320 | GNUNET_meta_data_destroy (fi.meta); | 405 | GNUNET_CRYPTO_hash (&pub, |
321 | return GNUNET_SYSERR; | 406 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), |
322 | } | 407 | &sm[i].query); |
323 | if (sqc->spcb != NULL) | 408 | sc->requests[i].query = sm[i].query; |
324 | { | 409 | GNUNET_CRYPTO_hash (keyword, |
325 | ret = sqc->spcb (&fi, key, isRoot, sqc->spcbClosure); | 410 | strlen (keyword), |
326 | if (ret == GNUNET_SYSERR) | 411 | &sc->requests[i].key); |
327 | sqc->aborted = GNUNET_YES; | 412 | } |
328 | } | 413 | } |
329 | else | 414 | else |
330 | ret = GNUNET_OK; | ||
331 | if ((strlen (id) > 0) && (strlen (uris) > 0)) | ||
332 | { | 415 | { |
333 | updateURI.type = sks; | 416 | msize = sizeof (struct SearchMessage); |
334 | GNUNET_hash (&sb->subspace, | 417 | GNUNET_assert (size >= msize); |
335 | sizeof (GNUNET_RSA_PublicKey), | 418 | sm = buf; |
336 | &updateURI.data.sks.namespace); | 419 | memset (sm, 0, msize); |
337 | updateURI.data.sks.identifier = GNUNET_strdup (id); | 420 | sm->header.size = htons (sizeof (struct SearchMessage)); |
338 | add_search_for_uri (&updateURI, sqc); | 421 | sm->header.type = htons (GNUNET_MESSAGE_TYPE_FS_START_SEARCH); |
339 | GNUNET_free (updateURI.data.sks.identifier); | 422 | sm->anonymity_level = htonl (sc->anonymity); |
423 | sm->target = sc->uri->data.sks.namespace; | ||
424 | identifier = sc->uri->data.sks.identifier; | ||
425 | GNUNET_CRYPTO_hash (identifier, | ||
426 | strlen (identifier), | ||
427 | &idh); | ||
428 | GNUNET_CRYPTO_hash_xor (&idh, | ||
429 | &sm->target, | ||
430 | &sm->query); | ||
340 | } | 431 | } |
341 | GNUNET_meta_data_destroy (fi.meta); | 432 | GNUNET_CLIENT_receive (sc->client, |
342 | GNUNET_ECRS_uri_destroy (fi.uri); | 433 | &receive_results, |
343 | return ret; | 434 | sc, |
435 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
436 | return msize; | ||
344 | } | 437 | } |
345 | 438 | ||
439 | |||
346 | /** | 440 | /** |
347 | * Process replies received in response to our | 441 | * Reconnect to the FS service and transmit |
348 | * queries. Verifies, decrypts and passes valid | 442 | * our queries NOW. |
349 | * replies to the callback. | ||
350 | * | 443 | * |
351 | * @return GNUNET_SYSERR if the entry is malformed | 444 | * @param cls our search context |
445 | * @param tc unused | ||
352 | */ | 446 | */ |
353 | static int | 447 | static void |
354 | receive_response_callback (const GNUNET_HashCode * key, | 448 | do_reconnect (void *cls, |
355 | const GNUNET_DatastoreValue * value, | 449 | const struct GNUNET_SCHEDULER_TaskContext *tc) |
356 | void *cls, unsigned long long uid) | ||
357 | { | 450 | { |
358 | struct PendingSearch *ps = cls; | 451 | struct GNUNET_FS_SearchContext *sc = cls; |
359 | struct GNUNET_ECRS_SearchContext *sqc = ps->context; | 452 | struct GNUNET_CLIENT_Connection *client; |
360 | struct GNUNET_GE_Context *ectx = sqc->ectx; | 453 | size_t size; |
361 | unsigned int type; | 454 | |
362 | GNUNET_ECRS_FileInfo fi; | 455 | sc->task = GNUNET_SCHEDULER_NO_TASK; |
363 | unsigned int size; | 456 | client = GNUNET_CLIENT_connect (sc->h->sched, |
364 | int ret; | 457 | "fs", |
365 | GNUNET_HashCode query; | 458 | sc->h->cfg); |
366 | GNUNET_CronTime expiration; | 459 | if (NULL == client) |
367 | |||
368 | expiration = GNUNET_ntohll (value->expiration_time); | ||
369 | if (expiration < GNUNET_get_time ()) | ||
370 | return GNUNET_OK; /* expired, ignore! */ | ||
371 | type = ntohl (value->type); | ||
372 | size = ntohl (value->size) - sizeof (GNUNET_DatastoreValue); | ||
373 | #if DEBUG_SEARCH | ||
374 | GNUNET_GE_LOG (ectx, | ||
375 | GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER, | ||
376 | "Search received reply of type %u and size %u.\n", type, | ||
377 | size); | ||
378 | #endif | ||
379 | if (GNUNET_OK != | ||
380 | GNUNET_EC_file_block_check_and_get_query (size, | ||
381 | (const GNUNET_EC_DBlock *) | ||
382 | &value[1], GNUNET_YES, | ||
383 | &query)) | ||
384 | { | 460 | { |
385 | GNUNET_GE_BREAK_OP (NULL, 0); | 461 | try_reconnect (sc); |
386 | return GNUNET_SYSERR; | 462 | return; |
387 | } | ||
388 | if (!((0 == memcmp (&query, | ||
389 | (GNUNET_HashCode *) & ps[1], sizeof (GNUNET_HashCode))) | ||
390 | && ((ps->type == type) || (ps->type == GNUNET_ECRS_BLOCKTYPE_ANY)) | ||
391 | && (GNUNET_YES == | ||
392 | GNUNET_EC_is_block_applicable_for_query (type, size, | ||
393 | (const GNUNET_EC_DBlock | ||
394 | *) &value[1], &query, | ||
395 | ps->keyCount, | ||
396 | (GNUNET_HashCode *) & | ||
397 | ps[1])))) | ||
398 | { | ||
399 | return GNUNET_OK; /* not a match */ | ||
400 | } | 463 | } |
464 | sc->client = client; | ||
465 | if (GNUNET_FS_uri_test_ksk (sc->uri)) | ||
466 | size = sizeof (struct SearchMessage) * sc->uri->data.ksk.keywordCount; | ||
467 | else | ||
468 | size = sizeof (struct SearchMessage); | ||
469 | GNUNET_CLIENT_notify_transmit_ready (client, | ||
470 | size, | ||
471 | GNUNET_CONSTANTS_SERVICE_TIMEOUT, | ||
472 | &transmit_search_request, | ||
473 | sc); | ||
474 | } | ||
401 | 475 | ||
402 | switch (type) | 476 | |
477 | /** | ||
478 | * Shutdown any existing connection to the FS | ||
479 | * service and try to establish a fresh one | ||
480 | * (and then re-transmit our search request). | ||
481 | * | ||
482 | * @param sc the search to reconnec | ||
483 | */ | ||
484 | static void | ||
485 | try_reconnect (struct GNUNET_FS_SearchContext *sc) | ||
486 | { | ||
487 | if (NULL != sc->client) | ||
403 | { | 488 | { |
404 | case GNUNET_ECRS_BLOCKTYPE_KEYWORD: | 489 | GNUNET_CLIENT_disconnect (sc->client); |
405 | { | 490 | sc->client = NULL; |
406 | GNUNET_EC_KBlock *kb; | 491 | } |
407 | const char *dstURI; | 492 | sc->task |
408 | #if DEBUG_SEARCH | 493 | = GNUNET_SCHEDULER_add_delayed (sc->h->sched, |
409 | GNUNET_EncName enc; | 494 | GNUNET_NO, |
410 | #endif | 495 | GNUNET_SCHEDULER_PRIORITY_IDLE, |
411 | int j; | 496 | GNUNET_SCHEDULER_NO_TASK, |
412 | 497 | GNUNET_TIME_UNIT_SECONDS, | |
413 | if (size < sizeof (GNUNET_EC_KBlock)) | 498 | &do_reconnect, |
414 | { | 499 | sc); |
415 | GNUNET_GE_BREAK_OP (NULL, 0); | ||
416 | return GNUNET_SYSERR; | ||
417 | } | ||
418 | kb = GNUNET_malloc (size); | ||
419 | memcpy (kb, &value[1], size); | ||
420 | #if DEBUG_SEARCH | ||
421 | IF_GELOG (ectx, | ||
422 | GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | | ||
423 | GNUNET_GE_USER, GNUNET_hash_to_enc (&ps->decryptKey, &enc)); | ||
424 | GNUNET_GE_LOG (ectx, | ||
425 | GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | | ||
426 | GNUNET_GE_USER, | ||
427 | "Decrypting KBlock with key %s.\n", &enc); | ||
428 | #endif | ||
429 | GNUNET_ECRS_decryptInPlace (&ps->decryptKey, | ||
430 | &kb[1], size - sizeof (GNUNET_EC_KBlock)); | ||
431 | j = sizeof (GNUNET_EC_KBlock); | ||
432 | while ((j < size) && (((const char *) kb)[j] != '\0')) | ||
433 | j++; | ||
434 | if (j == size) | ||
435 | { | ||
436 | GNUNET_GE_BREAK_OP (ectx, 0); /* kblock malformed */ | ||
437 | GNUNET_free (kb); | ||
438 | return GNUNET_SYSERR; | ||
439 | } | ||
440 | dstURI = (const char *) &kb[1]; | ||
441 | j++; | ||
442 | fi.meta = GNUNET_meta_data_deserialize (ectx, | ||
443 | &((const char *) | ||
444 | kb)[j], size - j); | ||
445 | if (fi.meta == NULL) | ||
446 | { | ||
447 | GNUNET_GE_BREAK_OP (ectx, 0); /* kblock malformed */ | ||
448 | GNUNET_free (kb); | ||
449 | return GNUNET_SYSERR; | ||
450 | } | ||
451 | fi.uri = GNUNET_ECRS_string_to_uri (ectx, dstURI); | ||
452 | if (fi.uri == NULL) | ||
453 | { | ||
454 | GNUNET_GE_BREAK_OP (ectx, 0); /* kblock malformed */ | ||
455 | GNUNET_meta_data_destroy (fi.meta); | ||
456 | GNUNET_free (kb); | ||
457 | return GNUNET_SYSERR; | ||
458 | } | ||
459 | if (sqc->spcb != NULL) | ||
460 | { | ||
461 | ret = sqc->spcb (&fi, | ||
462 | &ps->decryptKey, GNUNET_NO, sqc->spcbClosure); | ||
463 | if (ret == GNUNET_SYSERR) | ||
464 | sqc->aborted = GNUNET_YES; | ||
465 | } | ||
466 | else | ||
467 | ret = GNUNET_OK; | ||
468 | GNUNET_ECRS_uri_destroy (fi.uri); | ||
469 | GNUNET_meta_data_destroy (fi.meta); | ||
470 | GNUNET_free (kb); | ||
471 | return ret; | ||
472 | } | ||
473 | case GNUNET_ECRS_BLOCKTYPE_SIGNED: | ||
474 | { | ||
475 | GNUNET_EC_SBlock *sb; | ||
476 | int ret; | ||
477 | |||
478 | if (size < sizeof (GNUNET_EC_SBlock)) | ||
479 | { | ||
480 | GNUNET_GE_BREAK_OP (ectx, 0); /* sblock malformed */ | ||
481 | return GNUNET_SYSERR; | ||
482 | } | ||
483 | sb = GNUNET_malloc (size); | ||
484 | memcpy (sb, &value[1], size); | ||
485 | GNUNET_ECRS_decryptInPlace (&ps->decryptKey, | ||
486 | &sb[1], size - sizeof (GNUNET_EC_SBlock)); | ||
487 | ret = process_sblock_result (sb, &ps->decryptKey, size, sqc); | ||
488 | GNUNET_free (sb); | ||
489 | return ret; | ||
490 | } | ||
491 | case GNUNET_ECRS_BLOCKTYPE_KEYWORD_SIGNED: | ||
492 | { | ||
493 | GNUNET_EC_KSBlock *kb; | ||
494 | int ret; | ||
495 | |||
496 | if (size < sizeof (GNUNET_EC_KSBlock)) | ||
497 | { | ||
498 | GNUNET_GE_BREAK_OP (ectx, 0); /* ksblock malformed */ | ||
499 | return GNUNET_SYSERR; | ||
500 | } | ||
501 | kb = GNUNET_malloc (size); | ||
502 | memcpy (kb, &value[1], size); | ||
503 | GNUNET_ECRS_decryptInPlace (&ps->decryptKey, | ||
504 | &kb->sblock, | ||
505 | size - sizeof (GNUNET_EC_KBlock) - | ||
506 | sizeof (unsigned int)); | ||
507 | ret = | ||
508 | process_sblock_result (&kb->sblock, &ps->decryptKey, | ||
509 | size - sizeof (GNUNET_EC_KSBlock) + | ||
510 | sizeof (GNUNET_EC_SBlock), sqc); | ||
511 | GNUNET_free (kb); | ||
512 | return ret; | ||
513 | } | ||
514 | default: | ||
515 | GNUNET_GE_BREAK_OP (ectx, 0); | ||
516 | break; | ||
517 | } /* end switch */ | ||
518 | return GNUNET_OK; | ||
519 | } | 500 | } |
520 | 501 | ||
502 | |||
521 | /** | 503 | /** |
522 | * Start search for content. | 504 | * Start search for content. |
523 | * | 505 | * |
524 | * @param uri specifies the search parameters | 506 | * @param h handle to the file sharing subsystem |
525 | * @param uri set to the URI of the uploaded file | 507 | * @param uri specifies the search parameters; can be |
508 | * a KSK URI or an SKS URI. | ||
509 | * @param anonymity desired level of anonymity | ||
510 | * @return context that can be used to control the search | ||
526 | */ | 511 | */ |
527 | struct GNUNET_ECRS_SearchContext * | 512 | struct GNUNET_FS_SearchContext * |
528 | GNUNET_ECRS_search_start (struct GNUNET_GE_Context *ectx, | 513 | GNUNET_FS_search_start (struct GNUNET_FS_Handle *h, |
529 | struct GNUNET_GC_Configuration *cfg, | 514 | const struct GNUNET_FS_Uri *uri, |
530 | struct GNUNET_FS_SearchContext *sc, | 515 | unsigned int anonymity) |
531 | const struct GNUNET_ECRS_URI *uri, | ||
532 | unsigned int anonymityLevel, | ||
533 | GNUNET_ECRS_SearchResultProcessor spcb, | ||
534 | void *spcbClosure) | ||
535 | { | 516 | { |
536 | struct GNUNET_ECRS_SearchContext *ctx; | 517 | struct GNUNET_FS_SearchContext *sc; |
518 | struct GNUNET_CLIENT_Connection *client; | ||
519 | size_t size; | ||
537 | 520 | ||
538 | if (GNUNET_YES == GNUNET_ECRS_uri_test_ksk (uri)) | 521 | if (GNUNET_FS_uri_test_ksk (uri)) |
539 | { | 522 | { |
540 | if (1 != GNUNET_ECRS_uri_get_keyword_count_from_ksk (uri)) | 523 | size = sizeof (struct SearchMessage) * uri->data.ksk.keywordCount; |
541 | return NULL; | ||
542 | } | 524 | } |
543 | else | 525 | else |
544 | { | 526 | { |
545 | if (GNUNET_YES != GNUNET_ECRS_uri_test_sks (uri)) | 527 | GNUNET_assert (GNUNET_FS_uri_test_sks (uri)); |
546 | return NULL; | 528 | size = sizeof (struct SearchMessage); |
547 | } | 529 | } |
548 | ctx = GNUNET_malloc (sizeof (struct GNUNET_ECRS_SearchContext)); | 530 | if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE) |
549 | ctx->start = GNUNET_get_time (); | ||
550 | ctx->anonymityLevel = anonymityLevel; | ||
551 | ctx->ectx = ectx; | ||
552 | ctx->cfg = cfg; | ||
553 | ctx->queries = NULL; | ||
554 | ctx->spcb = spcb; | ||
555 | ctx->spcbClosure = spcbClosure; | ||
556 | ctx->aborted = GNUNET_NO; | ||
557 | ctx->sctx = sc == NULL ? GNUNET_FS_create_search_context (ectx, cfg) : sc; | ||
558 | if (ctx->sctx == NULL) | ||
559 | { | 531 | { |
560 | GNUNET_free (ctx); | 532 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
533 | _("Too many keywords specified for a single search.")); | ||
561 | return NULL; | 534 | return NULL; |
562 | } | 535 | } |
563 | ctx->my_sctx = (sc == NULL); | 536 | client = GNUNET_CLIENT_connect (sc->h->sched, |
564 | add_search_for_uri (uri, ctx); | 537 | "fs", |
565 | return ctx; | 538 | sc->h->cfg); |
539 | if (NULL == client) | ||
540 | return NULL; | ||
541 | sc = GNUNET_malloc (sizeof(struct GNUNET_FS_SearchContext)); | ||
542 | sc->h = h; | ||
543 | sc->uri = GNUNET_FS_uri_dup (uri); | ||
544 | sc->anonymity = anonymity; | ||
545 | sc->start_time = GNUNET_TIME_absolute_get (); | ||
546 | sc->client = client; | ||
547 | // FIXME: call callback! | ||
548 | GNUNET_CLIENT_notify_transmit_ready (client, | ||
549 | size, | ||
550 | GNUNET_CONSTANTS_SERVICE_TIMEOUT, | ||
551 | &transmit_search_request, | ||
552 | sc); | ||
553 | return sc; | ||
566 | } | 554 | } |
567 | 555 | ||
556 | |||
568 | /** | 557 | /** |
569 | * Stop search for content. | 558 | * Pause search. |
570 | * | 559 | * |
571 | * @param uri specifies the search parameters | 560 | * @param sc context for the search that should be paused |
572 | * @param uri set to the URI of the uploaded file | ||
573 | */ | 561 | */ |
574 | void | 562 | void |
575 | GNUNET_ECRS_search_stop (struct GNUNET_ECRS_SearchContext *ctx) | 563 | GNUNET_FS_search_pause (struct GNUNET_FS_SearchContext *sc) |
576 | { | 564 | { |
577 | struct PendingSearch *pos; | 565 | if (sc->task != GNUNET_SCHEDULER_NO_TASK) |
578 | 566 | GNUNET_SCHEDULER_cancel (sc->h->sched, | |
579 | while (ctx->queries != NULL) | 567 | sc->task); |
580 | { | 568 | sc->task = GNUNET_SCHEDULER_NO_TASK; |
581 | pos = ctx->queries; | 569 | if (NULL != sc->client) |
582 | ctx->queries = pos->next; | 570 | GNUNET_CLIENT_disconnect (sc->client); |
583 | if (!ctx->my_sctx) | 571 | sc->client = NULL; |
584 | GNUNET_FS_stop_search (ctx->sctx, &receive_response_callback, pos); | 572 | // FIXME: make persistent! |
585 | GNUNET_free (pos); | 573 | // FIXME: call callback! |
586 | } | ||
587 | if (ctx->my_sctx) | ||
588 | GNUNET_FS_destroy_search_context (ctx->sctx); | ||
589 | GNUNET_free (ctx); | ||
590 | } | 574 | } |
591 | 575 | ||
576 | |||
592 | /** | 577 | /** |
593 | * Search for content. | 578 | * Continue paused search. |
594 | * | 579 | * |
595 | * @param timeout how long to wait (relative) | 580 | * @param sc context for the search that should be resumed |
596 | * @param uri specifies the search parameters | ||
597 | * @param uri set to the URI of the uploaded file | ||
598 | */ | 581 | */ |
599 | int | 582 | void |
600 | GNUNET_ECRS_search (struct GNUNET_GE_Context *ectx, | 583 | GNUNET_FS_search_continue (struct GNUNET_FS_SearchContext *sc) |
601 | struct GNUNET_GC_Configuration *cfg, | ||
602 | const struct GNUNET_ECRS_URI *uri, | ||
603 | unsigned int anonymityLevel, | ||
604 | GNUNET_ECRS_SearchResultProcessor spcb, | ||
605 | void *spcbClosure, GNUNET_ECRS_TestTerminate tt, | ||
606 | void *ttClosure) | ||
607 | { | 584 | { |
608 | struct GNUNET_ECRS_SearchContext *ctx; | 585 | GNUNET_assert (sc->client == NULL); |
609 | 586 | GNUNET_assert (sc->task == GNUNET_SCHEDULER_NO_TASK); | |
610 | ctx = | 587 | do_reconnect (sc, NULL); |
611 | GNUNET_ECRS_search_start (ectx, cfg, NULL, | 588 | // FIXME: make persistent! |
612 | uri, anonymityLevel, spcb, spcbClosure); | 589 | // FIXME: call callback! |
613 | if (ctx == NULL) | ||
614 | return GNUNET_SYSERR; | ||
615 | while (((NULL == tt) || (GNUNET_OK == tt (ttClosure))) | ||
616 | && (GNUNET_NO == GNUNET_shutdown_test ()) | ||
617 | && (ctx->aborted == GNUNET_NO)) | ||
618 | GNUNET_thread_sleep (100 * GNUNET_CRON_MILLISECONDS); | ||
619 | GNUNET_ECRS_search_stop (ctx); | ||
620 | return GNUNET_OK; | ||
621 | } | 590 | } |
622 | 591 | ||
623 | #endif | 592 | |
593 | /** | ||
594 | * Stop search for content. | ||
595 | * | ||
596 | * @param sc context for the search that should be stopped | ||
597 | */ | ||
598 | void | ||
599 | GNUNET_FS_search_stop (struct GNUNET_FS_SearchContext *sc) | ||
600 | { | ||
601 | // FIXME: make un-persistent! | ||
602 | // FIXME: call callback! | ||
603 | if (sc->task != GNUNET_SCHEDULER_NO_TASK) | ||
604 | GNUNET_SCHEDULER_cancel (sc->h->sched, | ||
605 | sc->task); | ||
606 | if (NULL != sc->client) | ||
607 | GNUNET_CLIENT_disconnect (sc->client); | ||
608 | GNUNET_free_non_null (sc->requests); | ||
609 | GNUNET_FS_uri_destroy (sc->uri); | ||
610 | GNUNET_free (sc); | ||
611 | } | ||
624 | 612 | ||
625 | /* end of fs_search.c */ | 613 | /* end of fs_search.c */ |
diff --git a/src/fs/fs_unindex.c b/src/fs/fs_unindex.c index fb72c0167..23779bc97 100644 --- a/src/fs/fs_unindex.c +++ b/src/fs/fs_unindex.c | |||
@@ -79,54 +79,6 @@ unindex_reader (void *cls, | |||
79 | 79 | ||
80 | 80 | ||
81 | /** | 81 | /** |
82 | * Function called asking for the current (encoded) | ||
83 | * block to be processed. After processing the | ||
84 | * client should either call "GNUNET_FS_tree_encode_next" | ||
85 | * or (on error) "GNUNET_FS_tree_encode_finish". | ||
86 | * | ||
87 | * @param cls closure | ||
88 | * @param query the query for the block (key for lookup in the datastore) | ||
89 | * @param offset offset of the block | ||
90 | * @param type type of the block (IBLOCK or DBLOCK) | ||
91 | * @param block the (encrypted) block | ||
92 | * @param block_size size of block (in bytes) | ||
93 | */ | ||
94 | static void | ||
95 | unindex_process (void *cls, | ||
96 | const GNUNET_HashCode *query, | ||
97 | uint64_t offset, | ||
98 | unsigned int type, | ||
99 | const void *block, | ||
100 | uint16_t block_size) | ||
101 | { | ||
102 | struct GNUNET_FS_UnindexContext *uc = cls; | ||
103 | uint32_t size; | ||
104 | const void *data; | ||
105 | struct OnDemandBlock odb; | ||
106 | |||
107 | if (type != GNUNET_DATASTORE_BLOCKTYPE_DBLOCK) | ||
108 | { | ||
109 | size = block_size; | ||
110 | data = block; | ||
111 | } | ||
112 | else /* on-demand encoded DBLOCK */ | ||
113 | { | ||
114 | size = sizeof(struct OnDemandBlock); | ||
115 | odb.offset = offset; | ||
116 | odb.file_id = uc->file_id; | ||
117 | data = &odb; | ||
118 | } | ||
119 | GNUNET_DATASTORE_remove (uc->dsh, | ||
120 | query, | ||
121 | block_size, | ||
122 | block, | ||
123 | &process_cont, | ||
124 | uc, | ||
125 | GNUNET_CONSTANTS_SERVICE_TIMEOUT); | ||
126 | } | ||
127 | |||
128 | |||
129 | /** | ||
130 | * Fill in all of the generic fields for | 82 | * Fill in all of the generic fields for |
131 | * an unindex event. | 83 | * an unindex event. |
132 | * | 84 | * |
@@ -223,7 +175,7 @@ process_cont (void *cls, | |||
223 | if (success == GNUNET_SYSERR) | 175 | if (success == GNUNET_SYSERR) |
224 | { | 176 | { |
225 | signal_unindex_error (uc, | 177 | signal_unindex_error (uc, |
226 | emsg); | 178 | msg); |
227 | return; | 179 | return; |
228 | } | 180 | } |
229 | 181 | ||
@@ -232,6 +184,54 @@ process_cont (void *cls, | |||
232 | 184 | ||
233 | 185 | ||
234 | /** | 186 | /** |
187 | * Function called asking for the current (encoded) | ||
188 | * block to be processed. After processing the | ||
189 | * client should either call "GNUNET_FS_tree_encode_next" | ||
190 | * or (on error) "GNUNET_FS_tree_encode_finish". | ||
191 | * | ||
192 | * @param cls closure | ||
193 | * @param query the query for the block (key for lookup in the datastore) | ||
194 | * @param offset offset of the block | ||
195 | * @param type type of the block (IBLOCK or DBLOCK) | ||
196 | * @param block the (encrypted) block | ||
197 | * @param block_size size of block (in bytes) | ||
198 | */ | ||
199 | static void | ||
200 | unindex_process (void *cls, | ||
201 | const GNUNET_HashCode *query, | ||
202 | uint64_t offset, | ||
203 | unsigned int type, | ||
204 | const void *block, | ||
205 | uint16_t block_size) | ||
206 | { | ||
207 | struct GNUNET_FS_UnindexContext *uc = cls; | ||
208 | uint32_t size; | ||
209 | const void *data; | ||
210 | struct OnDemandBlock odb; | ||
211 | |||
212 | if (type != GNUNET_DATASTORE_BLOCKTYPE_DBLOCK) | ||
213 | { | ||
214 | size = block_size; | ||
215 | data = block; | ||
216 | } | ||
217 | else /* on-demand encoded DBLOCK */ | ||
218 | { | ||
219 | size = sizeof(struct OnDemandBlock); | ||
220 | odb.offset = offset; | ||
221 | odb.file_id = uc->file_id; | ||
222 | data = &odb; | ||
223 | } | ||
224 | GNUNET_DATASTORE_remove (uc->dsh, | ||
225 | query, | ||
226 | block_size, | ||
227 | block, | ||
228 | &process_cont, | ||
229 | uc, | ||
230 | GNUNET_CONSTANTS_SERVICE_TIMEOUT); | ||
231 | } | ||
232 | |||
233 | |||
234 | /** | ||
235 | * Function called when the tree encoder has | 235 | * Function called when the tree encoder has |
236 | * processed all blocks. Clean up. | 236 | * processed all blocks. Clean up. |
237 | * | 237 | * |
diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h index ad8e28bd1..664b10636 100644 --- a/src/include/gnunet_protocols.h +++ b/src/include/gnunet_protocols.h | |||
@@ -409,6 +409,16 @@ extern "C" | |||
409 | */ | 409 | */ |
410 | #define GNUNET_MESSAGE_TYPE_FS_UNINDEX_OK 135 | 410 | #define GNUNET_MESSAGE_TYPE_FS_UNINDEX_OK 135 |
411 | 411 | ||
412 | /** | ||
413 | * Client asks FS service to start a (keyword) search. | ||
414 | */ | ||
415 | #define GNUNET_MESSAGE_TYPE_FS_START_SEARCH 136 | ||
416 | |||
417 | /** | ||
418 | * FS service has found content matching this client's | ||
419 | * request. | ||
420 | */ | ||
421 | #define GNUNET_MESSAGE_TYPE_FS_CONTENT 137 | ||
412 | 422 | ||
413 | /* | 423 | /* |
414 | TODO: | 424 | TODO: |