aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2009-09-04 08:12:54 +0000
committerChristian Grothoff <christian@grothoff.org>2009-09-04 08:12:54 +0000
commitf8bfdee4d3a12ccc63b4f340b3032ae3b0ee5fd1 (patch)
treee7f08426d4d44a4e68d974f51155c739d9127ccb /src
parent0624f202f56751abbccb16f08031c03b20a921a9 (diff)
downloadgnunet-f8bfdee4d3a12ccc63b4f340b3032ae3b0ee5fd1.tar.gz
gnunet-f8bfdee4d3a12ccc63b4f340b3032ae3b0ee5fd1.zip
towards search
Diffstat (limited to 'src')
-rw-r--r--src/fs/fs.h160
-rw-r--r--src/fs/fs_search.c984
-rw-r--r--src/fs/fs_unindex.c98
-rw-r--r--src/include/gnunet_protocols.h10
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 */
589struct 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 */
588struct GNUNET_FS_SearchContext 607struct 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 */
883struct 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 */
940struct 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 */
43struct GNUNET_FS_SearchContext * 54static void
44GNUNET_FS_search_start (struct GNUNET_FS_Handle *h, 55process_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
57void 73 * @param uri the URI that was found
58GNUNET_FS_search_pause (struct GNUNET_FS_SearchContext *sc) 74 * @param meta metadata associated with the URI
75 */
76static void
77process_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 */
67void 107static void
68GNUNET_FS_search_continue (struct GNUNET_FS_SearchContext *sc) 108process_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 */
78void 184static void
79GNUNET_FS_search_stop (struct GNUNET_FS_SearchContext *sc) 185process_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 */
92struct PendingSearch 256static void
257process_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 */
115struct GNUNET_ECRS_SearchContext 315static void
116{ 316try_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
153static int
154receive_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 */
161static void
162add_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 */
193static void 326static void
194add_search_for_uri (const struct GNUNET_ECRS_URI *uri, 327receive_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 */
275static int 365static size_t
276process_sblock_result (const GNUNET_EC_SBlock * sb, 366transmit_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 */
353static int 447static void
354receive_response_callback (const GNUNET_HashCode * key, 448do_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 */
484static void
485try_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 */
527struct GNUNET_ECRS_SearchContext * 512struct GNUNET_FS_SearchContext *
528GNUNET_ECRS_search_start (struct GNUNET_GE_Context *ectx, 513GNUNET_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 */
574void 562void
575GNUNET_ECRS_search_stop (struct GNUNET_ECRS_SearchContext *ctx) 563GNUNET_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 */
599int 582void
600GNUNET_ECRS_search (struct GNUNET_GE_Context *ectx, 583GNUNET_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 */
598void
599GNUNET_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 */
94static void
95unindex_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 */
199static void
200unindex_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: