diff options
Diffstat (limited to 'src/fs/fs_uri.c')
-rw-r--r-- | src/fs/fs_uri.c | 1317 |
1 files changed, 1317 insertions, 0 deletions
diff --git a/src/fs/fs_uri.c b/src/fs/fs_uri.c new file mode 100644 index 000000000..863ab475d --- /dev/null +++ b/src/fs/fs_uri.c | |||
@@ -0,0 +1,1317 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 2, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file fs/fs_uri.c | ||
23 | * @brief Parses and produces uri strings. | ||
24 | * @author Igor Wronsky, Christian Grothoff | ||
25 | * | ||
26 | * GNUnet URIs are of the general form "gnunet://MODULE/IDENTIFIER". | ||
27 | * The specific structure of "IDENTIFIER" depends on the module and | ||
28 | * maybe differenciated into additional subcategories if applicable. | ||
29 | * This module only deals with ecrs identifiers (MODULE = "ecrs"). | ||
30 | * <p> | ||
31 | * | ||
32 | * This module only parses URIs for the AFS module. The ECRS URIs fall | ||
33 | * into four categories, "chk", "sks", "ksk" and "loc". The first three | ||
34 | * categories were named in analogy (!) to Freenet, but they do NOT | ||
35 | * work in exactly the same way. They are very similar from the user's | ||
36 | * point of view (unique file identifier, subspace, keyword), but the | ||
37 | * implementation is rather different in pretty much every detail. | ||
38 | * The concrete URI formats are: | ||
39 | * | ||
40 | * <ul><li> | ||
41 | * | ||
42 | * First, there are URIs that identify a file. They have the format | ||
43 | * "gnunet://ecrs/chk/HEX1.HEX2.SIZE". These URIs can be used to | ||
44 | * download the file. The description, filename, mime-type and other | ||
45 | * meta-data is NOT part of the file-URI since a URI uniquely | ||
46 | * identifies a resource (and the contents of the file would be the | ||
47 | * same even if it had a different description). | ||
48 | * | ||
49 | * </li><li> | ||
50 | * | ||
51 | * The second category identifies entries in a namespace. The format | ||
52 | * is "gnunet://ecrs/sks/NAMESPACE/IDENTIFIER" where the namespace | ||
53 | * should be given in HEX. Applications may allow using a nickname | ||
54 | * for the namespace if the nickname is not ambiguous. The identifier | ||
55 | * can be either an ASCII sequence or a HEX-encoding. If the | ||
56 | * identifier is in ASCII but the format is ambiguous and could denote | ||
57 | * a HEX-string a "/" is appended to indicate ASCII encoding. | ||
58 | * | ||
59 | * </li> <li> | ||
60 | * | ||
61 | * The third category identifies ordinary searches. The format is | ||
62 | * "gnunet://ecrs/ksk/KEYWORD[+KEYWORD]*". Using the "+" syntax | ||
63 | * it is possible to encode searches with the boolean "AND" operator. | ||
64 | * "+" is used since it indicates a commutative 'and' operation and | ||
65 | * is unlikely to be used in a keyword by itself. | ||
66 | * | ||
67 | * </li><li> | ||
68 | * | ||
69 | * The last category identifies a datum on a specific machine. The | ||
70 | * format is "gnunet://ecrs/loc/HEX1.HEX2.SIZE.PEER.SIG.EXPTIME". PEER is | ||
71 | * the BinName of the public key of the peer storing the datum. The | ||
72 | * signature (SIG) certifies that this peer has this content. | ||
73 | * HEX1, HEX2 and SIZE correspond to a 'chk' URI. | ||
74 | * | ||
75 | * </li></ul> | ||
76 | * | ||
77 | * The encoding for hexadecimal values is defined in the hashing.c | ||
78 | * module in the gnunetutil library and discussed there. | ||
79 | * <p> | ||
80 | */ | ||
81 | #include "platform.h" | ||
82 | #include "gnunet_fs_lib.h" | ||
83 | #include "fs.h" | ||
84 | |||
85 | |||
86 | /** | ||
87 | * Get a unique key from a URI. This is for putting URIs | ||
88 | * into HashMaps. The key may change between FS implementations. | ||
89 | * | ||
90 | * @param uri uri to convert to a unique key | ||
91 | * @param key wherer to store the unique key | ||
92 | */ | ||
93 | void | ||
94 | GNUNET_FS_uri_to_key (const struct GNUNET_FS_Uri *uri, | ||
95 | GNUNET_HashCode * key) | ||
96 | { | ||
97 | switch (uri->type) | ||
98 | { | ||
99 | case chk: | ||
100 | *key = uri->data.fi.chk.query; | ||
101 | return; | ||
102 | case sks: | ||
103 | GNUNET_hash (uri->data.sks.identifier, | ||
104 | strlen (uri->data.sks.identifier), key); | ||
105 | break; | ||
106 | case ksk: | ||
107 | if (uri->data.ksk.keywordCount > 0) | ||
108 | GNUNET_hash (uri->data.ksk.keywords[0], | ||
109 | strlen (uri->data.ksk.keywords[0]), key); | ||
110 | break; | ||
111 | case loc: | ||
112 | GNUNET_hash (&uri->data.loc.fi, | ||
113 | sizeof (GNUNET_EC_FileIdentifier) + | ||
114 | sizeof (GNUNET_RSA_PublicKey), key); | ||
115 | break; | ||
116 | default: | ||
117 | memset (key, 0, sizeof (GNUNET_HashCode)); | ||
118 | break; | ||
119 | } | ||
120 | } | ||
121 | |||
122 | |||
123 | /** | ||
124 | * Convert a URI to a UTF-8 String. | ||
125 | * | ||
126 | * @param uri uri to convert to a string | ||
127 | * @return the UTF-8 string | ||
128 | */ | ||
129 | char * | ||
130 | GNUNET_FS_uri_to_string (const struct GNUNET_FS_Uri *uri); | ||
131 | |||
132 | |||
133 | /** | ||
134 | * Convert keyword URI to a human readable format | ||
135 | * (i.e. the search query that was used in the first place) | ||
136 | * | ||
137 | * @param uri ksk uri to convert to a string | ||
138 | * @return string with the keywords | ||
139 | */ | ||
140 | char * | ||
141 | GNUNET_FS_uri_ksk_to_string_fancy (const struct GNUNET_FS_Uri *uri); | ||
142 | |||
143 | /** | ||
144 | * Convert a UTF-8 String to a URI. | ||
145 | * | ||
146 | * @param uri string to parse | ||
147 | * @param emsg where to store the parser error message (if any) | ||
148 | * @return NULL on error | ||
149 | */ | ||
150 | struct GNUNET_FS_Uri * | ||
151 | GNUNET_FS_uri_parse (const char *uri, | ||
152 | char **emsg); | ||
153 | |||
154 | /** | ||
155 | * Free URI. | ||
156 | * | ||
157 | * @param uri uri to free | ||
158 | */ | ||
159 | void | ||
160 | GNUNET_FS_uri_destroy (struct GNUNET_FS_Uri *uri) | ||
161 | { | ||
162 | unsigned int i; | ||
163 | |||
164 | GNUNET_assert (uri != NULL); | ||
165 | switch (uri->type) | ||
166 | { | ||
167 | case ksk: | ||
168 | for (i = 0; i < uri->data.ksk.keywordCount; i++) | ||
169 | GNUNET_free (uri->data.ksk.keywords[i]); | ||
170 | GNUNET_array_grow (uri->data.ksk.keywords, uri->data.ksk.keywordCount, | ||
171 | 0); | ||
172 | break; | ||
173 | case sks: | ||
174 | GNUNET_free (uri->data.sks.identifier); | ||
175 | break; | ||
176 | case loc: | ||
177 | break; | ||
178 | default: | ||
179 | /* do nothing */ | ||
180 | break; | ||
181 | } | ||
182 | GNUNET_free (uri); | ||
183 | } | ||
184 | |||
185 | /** | ||
186 | * How many keywords are ANDed in this keyword URI? | ||
187 | * | ||
188 | * @param uri ksk uri to get the number of keywords from | ||
189 | * @return 0 if this is not a keyword URI | ||
190 | */ | ||
191 | unsigned int | ||
192 | GNUNET_FS_uri_ksk_get_keyword_count (const struct GNUNET_FS_Uri *uri) | ||
193 | { | ||
194 | if (uri->type != ksk) | ||
195 | return 0; | ||
196 | return uri->data.ksk.keywordCount; | ||
197 | } | ||
198 | |||
199 | |||
200 | /** | ||
201 | * Iterate over all keywords in this keyword URI. | ||
202 | * | ||
203 | * @param uri ksk uri to get the keywords from | ||
204 | * @param iterator function to call on each keyword | ||
205 | * @param iterator_cls closure for iterator | ||
206 | * @return -1 if this is not a keyword URI, otherwise number of | ||
207 | * keywords iterated over until iterator aborted | ||
208 | */ | ||
209 | int | ||
210 | GNUNET_FS_uri_ksk_get_keywords (const struct GNUNET_FS_Uri *uri, | ||
211 | GNUNET_FS_KeywordIterator iterator, | ||
212 | void *iterator_cls) | ||
213 | { | ||
214 | unsigned int i; | ||
215 | char *keyword; | ||
216 | |||
217 | if (uri->type != ksk) | ||
218 | return -1; | ||
219 | if (iterator == NULL) | ||
220 | return uri->data.ksk.keywordCount; | ||
221 | for (i = 0; i < uri->data.ksk.keywordCount; i++) | ||
222 | { | ||
223 | keyword = uri->data.ksk.keywords[i]; | ||
224 | /* first character of keyword indicates | ||
225 | if it is mandatory or not */ | ||
226 | if (GNUNET_OK != iterator (&keyword[1], keyword[0] == '+', cls)) | ||
227 | return i; | ||
228 | } | ||
229 | return i; | ||
230 | } | ||
231 | |||
232 | |||
233 | /** | ||
234 | * Obtain the identity of the peer offering the data | ||
235 | * | ||
236 | * @param uri the location URI to inspect | ||
237 | * @param peer where to store the identify of the peer (presumably) offering the content | ||
238 | * @return GNUNET_SYSERR if this is not a location URI, otherwise GNUNET_OK | ||
239 | */ | ||
240 | int | ||
241 | GNUNET_FS_uri_loc_get_peer_identity (const struct GNUNET_FS_Uri *uri, | ||
242 | struct GNUNET_PeerIdentity * peer) | ||
243 | { | ||
244 | if (uri->type != loc) | ||
245 | return GNUNET_SYSERR; | ||
246 | GNUNET_hash (&uri->data.loc.peer, sizeof (GNUNET_RSA_PublicKey), | ||
247 | &peer->hashPubKey); | ||
248 | return GNUNET_OK; | ||
249 | } | ||
250 | |||
251 | |||
252 | /** | ||
253 | * Obtain the URI of the content itself. | ||
254 | * | ||
255 | * @param uri location URI to get the content URI from | ||
256 | * @return NULL if argument is not a location URI | ||
257 | */ | ||
258 | struct GNUNET_FS_Uri * | ||
259 | GNUNET_FS_uri_loc_get_uri (const struct GNUNET_FS_Uri *uri) | ||
260 | { | ||
261 | struct GNUNET_ECRS_Uri *ret; | ||
262 | |||
263 | if (uri->type != loc) | ||
264 | return NULL; | ||
265 | ret = GNUNET_malloc (sizeof (struct GNUNET_ECRS_Uri)); | ||
266 | ret->type = chk; | ||
267 | ret->data.chk = uri->data.loc.fi; | ||
268 | return ret; | ||
269 | } | ||
270 | |||
271 | |||
272 | /** | ||
273 | * Construct a location URI (this peer will be used for the location). | ||
274 | * | ||
275 | * @param baseURI content offered by the sender | ||
276 | * @param cfg configuration information (used to find our hostkey) | ||
277 | * @param expiration_time how long will the content be offered? | ||
278 | * @return the location URI, NULL on error | ||
279 | */ | ||
280 | struct GNUNET_FS_Uri * | ||
281 | GNUNET_FS_uri_loc_create (const struct GNUNET_FS_Uri *baseUri, | ||
282 | struct GNUNET_CONFIGURATION_Handle *cfg, | ||
283 | struct GNUNET_TIME_Absolute expiration_time); | ||
284 | |||
285 | |||
286 | /** | ||
287 | * Canonicalize keyword URI. Performs operations such | ||
288 | * as decapitalization and removal of certain characters. | ||
289 | * (useful for search). | ||
290 | * | ||
291 | * @param uri the URI to canonicalize | ||
292 | * @return canonicalized version of the URI, NULL on error | ||
293 | */ | ||
294 | struct GNUNET_FS_Uri * | ||
295 | GNUNET_FS_uri_ksk_canonicalize (const struct GNUNET_FS_Uri *uri); | ||
296 | |||
297 | |||
298 | /** | ||
299 | * Merge the sets of keywords from two KSK URIs. | ||
300 | * (useful for merging the canonicalized keywords with | ||
301 | * the original keywords for sharing). | ||
302 | * | ||
303 | * @param u1 first uri | ||
304 | * @param u2 second uri | ||
305 | * @return merged URI, NULL on error | ||
306 | */ | ||
307 | struct GNUNET_FS_Uri * | ||
308 | GNUNET_FS_uri_ksk_merge (const struct GNUNET_FS_Uri *u1, | ||
309 | const struct GNUNET_FS_Uri *u2); | ||
310 | |||
311 | |||
312 | /** | ||
313 | * Duplicate URI. | ||
314 | * | ||
315 | * @param uri the URI to duplicate | ||
316 | * @return copy of the URI | ||
317 | */ | ||
318 | struct GNUNET_FS_Uri * | ||
319 | GNUNET_FS_uri_dup (const struct GNUNET_FS_Uri *uri) | ||
320 | { | ||
321 | struct GNUNET_ECRS_URI *ret; | ||
322 | unsigned int i; | ||
323 | |||
324 | ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); | ||
325 | memcpy (ret, uri, sizeof (struct GNUNET_FS_Uri)); | ||
326 | switch (ret->type) | ||
327 | { | ||
328 | case ksk: | ||
329 | if (ret->data.ksk.keywordCount > 0) | ||
330 | { | ||
331 | ret->data.ksk.keywords | ||
332 | = GNUNET_malloc (ret->data.ksk.keywordCount * sizeof (char *)); | ||
333 | for (i = 0; i < ret->data.ksk.keywordCount; i++) | ||
334 | ret->data.ksk.keywords[i] = | ||
335 | GNUNET_strdup (uri->data.ksk.keywords[i]); | ||
336 | } | ||
337 | else | ||
338 | ret->data.ksk.keywords = NULL; /* just to be sure */ | ||
339 | break; | ||
340 | case sks: | ||
341 | ret->data.sks.identifier = GNUNET_strdup (uri->data.sks.identifier); | ||
342 | break; | ||
343 | case loc: | ||
344 | break; | ||
345 | default: | ||
346 | break; | ||
347 | } | ||
348 | return ret; | ||
349 | } | ||
350 | |||
351 | |||
352 | /** | ||
353 | * Create an FS URI from a single user-supplied string of keywords. | ||
354 | * The string is broken up at spaces into individual keywords. | ||
355 | * Keywords that start with "+" are mandatory. Double-quotes can | ||
356 | * be used to prevent breaking up strings at spaces (and also | ||
357 | * to specify non-mandatory keywords starting with "+"). | ||
358 | * | ||
359 | * Keywords must contain a balanced number of double quotes and | ||
360 | * double quotes can not be used in the actual keywords (for | ||
361 | * example, the string '""foo bar""' will be turned into two | ||
362 | * "OR"ed keywords 'foo' and 'bar', not into '"foo bar"'. | ||
363 | * | ||
364 | * @param keywords the keyword string | ||
365 | * @return an FS URI for the given keywords, NULL | ||
366 | * if keywords is not legal (i.e. empty). | ||
367 | */ | ||
368 | struct GNUNET_FS_Uri * | ||
369 | GNUNET_FS_uri_ksk_create (const char *keywords); | ||
370 | |||
371 | |||
372 | /** | ||
373 | * Create an FS URI from a user-supplied command line of keywords. | ||
374 | * Arguments should start with "+" to indicate mandatory | ||
375 | * keywords. | ||
376 | * | ||
377 | * @param argc number of keywords | ||
378 | * @param argv keywords (double quotes are not required for | ||
379 | * keywords containing spaces; however, double | ||
380 | * quotes are required for keywords starting with | ||
381 | * "+"); there is no mechanism for having double | ||
382 | * quotes in the actual keywords (if the user | ||
383 | * did specifically specify double quotes, the | ||
384 | * caller should convert each double quote | ||
385 | * into two single quotes). | ||
386 | * @return an FS URI for the given keywords, NULL | ||
387 | * if keywords is not legal (i.e. empty). | ||
388 | */ | ||
389 | struct GNUNET_FS_Uri * | ||
390 | GNUNET_FS_uri_ksk_create_from_args (unsigned int argc, | ||
391 | const char **argv); | ||
392 | |||
393 | |||
394 | /** | ||
395 | * Test if two URIs are equal. | ||
396 | * | ||
397 | * @param u1 one of the URIs | ||
398 | * @param u2 the other URI | ||
399 | * @return GNUNET_YES if the URIs are equal | ||
400 | */ | ||
401 | int | ||
402 | GNUNET_FS_uri_test_equal (const struct GNUNET_FS_Uri *u1, | ||
403 | const struct GNUNET_FS_Uri *u2) | ||
404 | { | ||
405 | int ret; | ||
406 | unsigned int i; | ||
407 | unsigned int j; | ||
408 | |||
409 | GNUNET_assert (uri1 != NULL); | ||
410 | GNUNET_assert (uri2 != NULL); | ||
411 | if (uri1->type != uri2->type) | ||
412 | return GNUNET_NO; | ||
413 | switch (uri1->type) | ||
414 | { | ||
415 | case chk: | ||
416 | if (0 == memcmp (&uri1->data.chk, | ||
417 | &uri2->data.chk, | ||
418 | sizeof (struct FileIdentifier))) | ||
419 | return GNUNET_YES; | ||
420 | return GNUNET_NO; | ||
421 | case sks: | ||
422 | if ((0 == memcmp (&uri1->data.sks.namespace, | ||
423 | &uri2->data.sks.namespace, | ||
424 | sizeof (GNUNET_HashCode))) && | ||
425 | (0 == strcmp (uri1->data.sks.identifier, | ||
426 | uri2->data.sks.identifier))) | ||
427 | |||
428 | return GNUNET_YES; | ||
429 | return GNUNET_NO; | ||
430 | case ksk: | ||
431 | if (uri1->data.ksk.keywordCount != uri2->data.ksk.keywordCount) | ||
432 | return GNUNET_NO; | ||
433 | for (i = 0; i < uri1->data.ksk.keywordCount; i++) | ||
434 | { | ||
435 | ret = GNUNET_NO; | ||
436 | for (j = 0; j < uri2->data.ksk.keywordCount; j++) | ||
437 | { | ||
438 | if (0 == strcmp (uri1->data.ksk.keywords[i], | ||
439 | uri2->data.ksk.keywords[j])) | ||
440 | { | ||
441 | ret = GNUNET_YES; | ||
442 | break; | ||
443 | } | ||
444 | } | ||
445 | if (ret == GNUNET_NO) | ||
446 | return GNUNET_NO; | ||
447 | } | ||
448 | return GNUNET_YES; | ||
449 | case loc: | ||
450 | if (memcmp (&uri1->data.loc, | ||
451 | &uri2->data.loc, | ||
452 | sizeof (struct FileIdentifier) + | ||
453 | sizeof (GNUNET_RSA_PublicKey) + | ||
454 | sizeof (struct GNUNET_TIME_Absolute) + | ||
455 | sizeof (unsigned short) + sizeof (unsigned short)) != 0) | ||
456 | return GNUNET_NO; | ||
457 | return GNUNET_YES; | ||
458 | default: | ||
459 | return GNUNET_NO; | ||
460 | } | ||
461 | } | ||
462 | |||
463 | |||
464 | /** | ||
465 | * Is this a namespace URI? | ||
466 | * | ||
467 | * @param uri the uri to check | ||
468 | * @return GNUNET_YES if this is an SKS uri | ||
469 | */ | ||
470 | int | ||
471 | GNUNET_FS_uri_test_sks (const struct GNUNET_FS_Uri *uri) | ||
472 | { | ||
473 | return uri->type == sks; | ||
474 | } | ||
475 | |||
476 | |||
477 | /** | ||
478 | * Get the ID of a namespace from the given | ||
479 | * namespace URI. | ||
480 | * | ||
481 | * @param uri the uri to get the namespace ID from | ||
482 | * @param nsid where to store the ID of the namespace | ||
483 | * @return GNUNET_OK on success | ||
484 | */ | ||
485 | int | ||
486 | GNUNET_FS_uri_sks_get_namespace (const struct GNUNET_FS_Uri *uri, | ||
487 | GNUNET_HashCode * nsid) | ||
488 | { | ||
489 | if (! GNUNET_FS_uri_test_sks (uri)) | ||
490 | { | ||
491 | GNUNET_break (0); | ||
492 | return GNUNET_SYSERR; | ||
493 | } | ||
494 | *id = uri->data.sks.namespace; | ||
495 | return GNUNET_OK; | ||
496 | } | ||
497 | |||
498 | |||
499 | /** | ||
500 | * Get the content identifier of an SKS URI. | ||
501 | * | ||
502 | * @param uri the sks uri | ||
503 | * @return NULL on error (not a valid SKS URI) | ||
504 | */ | ||
505 | char * | ||
506 | GNUNET_FS_uri_sks_get_content_id (const struct GNUNET_FS_Uri *uri) | ||
507 | { | ||
508 | if (!GNUNET_FS_uri_test_sks (uri)) | ||
509 | { | ||
510 | GNUNET_break (0); | ||
511 | return NULL; | ||
512 | } | ||
513 | return GNUNET_strdup (uri->data.sks.identifier); | ||
514 | } | ||
515 | |||
516 | |||
517 | /** | ||
518 | * Convert namespace URI to a human readable format | ||
519 | * (using the namespace description, if available). | ||
520 | * | ||
521 | * @param cfg configuration to use | ||
522 | * @param uri SKS uri to convert | ||
523 | * @return NULL on error (not an SKS URI) | ||
524 | */ | ||
525 | char * | ||
526 | GNUNET_FS_uri_sks_to_string_fancy (struct GNUNET_CONFIGURATION_Handle *cfg, | ||
527 | const struct GNUNET_FS_Uri *uri); | ||
528 | |||
529 | |||
530 | /** | ||
531 | * Is this a keyword URI? | ||
532 | * | ||
533 | * @param uri the uri | ||
534 | * @return GNUNET_YES if this is a KSK uri | ||
535 | */ | ||
536 | int | ||
537 | GNUNET_FS_uri_test_ksk (const struct GNUNET_FS_Uri *uri) | ||
538 | { | ||
539 | #if EXTRA_CHECKS | ||
540 | unsigned int i; | ||
541 | |||
542 | if (uri->type == ksk) | ||
543 | { | ||
544 | for (i = uri->data.ksk.keywordCount - 1; i >= 0; i--) | ||
545 | GNUNET_assert (uri->data.ksk.keywords[i] != NULL); | ||
546 | } | ||
547 | #endif | ||
548 | return uri->type == ksk; | ||
549 | } | ||
550 | |||
551 | |||
552 | /** | ||
553 | * Is this a file (or directory) URI? | ||
554 | * | ||
555 | * @param uri the uri to check | ||
556 | * @return GNUNET_YES if this is a CHK uri | ||
557 | */ | ||
558 | int | ||
559 | GNUNET_FS_uri_test_chk (const struct GNUNET_FS_Uri *uri) | ||
560 | { | ||
561 | return uri->type == chk; | ||
562 | } | ||
563 | |||
564 | |||
565 | /** | ||
566 | * What is the size of the file that this URI | ||
567 | * refers to? | ||
568 | * | ||
569 | * @param uri the CHK URI to inspect | ||
570 | * @return size of the file as specified in the CHK URI | ||
571 | */ | ||
572 | uint64_t | ||
573 | GNUNET_FS_uri_chk_get_file_size (const struct GNUNET_FS_Uri *uri) | ||
574 | { | ||
575 | switch (uri->type) | ||
576 | { | ||
577 | case chk: | ||
578 | return GNUNET_ntohll (uri->data.chk.file_length); | ||
579 | case loc: | ||
580 | return GNUNET_ntohll (uri->data.loc.fi.file_length); | ||
581 | default: | ||
582 | GNUNET_assert (0); | ||
583 | } | ||
584 | return 0; /* unreachable */ | ||
585 | } | ||
586 | |||
587 | |||
588 | /** | ||
589 | * Is this a location URI? | ||
590 | * | ||
591 | * @param uri the uri to check | ||
592 | * @return GNUNET_YES if this is a LOC uri | ||
593 | */ | ||
594 | int | ||
595 | GNUNET_FS_uri_test_loc (const struct GNUNET_FS_Uri *uri) | ||
596 | { | ||
597 | return uri->type == loc; | ||
598 | } | ||
599 | |||
600 | |||
601 | /** | ||
602 | * Function called on each value in the meta data. | ||
603 | * Adds it to the URI. | ||
604 | * | ||
605 | * @param cls URI to update | ||
606 | * @param type type of the meta data | ||
607 | * @param data value of the meta data | ||
608 | * @return GNUNET_OK (always) | ||
609 | */ | ||
610 | static int | ||
611 | gather_uri_data (void *cls, | ||
612 | EXTRACTOR_KeywordType type, | ||
613 | const char *data) | ||
614 | { | ||
615 | struct GNUNET_FS_Uri *uri = cls; | ||
616 | char *nkword; | ||
617 | int j; | ||
618 | |||
619 | for (j = uri->data.ksk.keywordCount - 1; j >= 0; j--) | ||
620 | if (0 == strcmp (&uri->data.ksk.keywords[j][1], data)) | ||
621 | return GNUNET_OK; | ||
622 | nkword = GNUNET_malloc (strlen (data) + 2); | ||
623 | strcpy (nkword, " "); /* not mandatory */ | ||
624 | strcat (nkword, data); | ||
625 | uri->data.ksk.keywords[uri->data.ksk.keywordCount++] = nkword; | ||
626 | return GNUNET_OK; | ||
627 | } | ||
628 | |||
629 | |||
630 | /** | ||
631 | * Construct a keyword-URI from meta-data (take all entries | ||
632 | * in the meta-data and construct one large keyword URI | ||
633 | * that lists all keywords that can be found in the meta-data). | ||
634 | * @deprecated | ||
635 | */ | ||
636 | struct GNUNET_FS_Uri * | ||
637 | GNUNET_FS_uri_ksk_create_from_meta_data (const struct GNUNET_MetaData *md) | ||
638 | { | ||
639 | struct GNUNET_FS_Uri *ret; | ||
640 | |||
641 | if (md == NULL) | ||
642 | return NULL; | ||
643 | ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); | ||
644 | ret->type = ksk; | ||
645 | ret->data.ksk.keywordCount = 0; | ||
646 | ret->data.ksk.keywords = NULL; | ||
647 | ret->data.ksk.keywords | ||
648 | = GNUNET_malloc (sizeof (char *) * | ||
649 | GNUNET_meta_data_get_contents (md, NULL, NULL)); | ||
650 | GNUNET_meta_data_get_contents (md, &gather_uri_data, ret); | ||
651 | return ret; | ||
652 | |||
653 | } | ||
654 | |||
655 | #if 0 | ||
656 | |||
657 | // old code... | ||
658 | |||
659 | |||
660 | |||
661 | /** | ||
662 | * In URI-encoding, does the given character | ||
663 | * need to be encoded using %-encoding? | ||
664 | */ | ||
665 | static int | ||
666 | needs_percent (char c) | ||
667 | { | ||
668 | return (!((isalnum (c)) || | ||
669 | (c == '-') || (c == '_') || (c == '.') || (c == '~'))); | ||
670 | } | ||
671 | |||
672 | /** | ||
673 | * Generate a keyword URI. | ||
674 | * @return NULL on error (i.e. keywordCount == 0) | ||
675 | */ | ||
676 | static char * | ||
677 | createKeywordURI (char **keywords, unsigned int keywordCount) | ||
678 | { | ||
679 | size_t n; | ||
680 | char *ret; | ||
681 | unsigned int i; | ||
682 | unsigned int j; | ||
683 | unsigned int wpos; | ||
684 | size_t slen; | ||
685 | const char *keyword; | ||
686 | |||
687 | n = | ||
688 | keywordCount + strlen (GNUNET_ECRS_URI_PREFIX) + | ||
689 | strlen (GNUNET_ECRS_SEARCH_INFIX) + 1; | ||
690 | for (i = 0; i < keywordCount; i++) | ||
691 | { | ||
692 | keyword = keywords[i]; | ||
693 | slen = strlen (keyword); | ||
694 | n += slen; | ||
695 | for (j = 0; j < slen; j++) | ||
696 | { | ||
697 | if ((j == 0) && (keyword[j] == ' ')) | ||
698 | { | ||
699 | n--; | ||
700 | continue; /* skip leading space */ | ||
701 | } | ||
702 | if (needs_percent (keyword[j])) | ||
703 | n += 2; /* will use %-encoding */ | ||
704 | } | ||
705 | } | ||
706 | ret = GNUNET_malloc (n); | ||
707 | strcpy (ret, GNUNET_ECRS_URI_PREFIX); | ||
708 | strcat (ret, GNUNET_ECRS_SEARCH_INFIX); | ||
709 | wpos = strlen (ret); | ||
710 | for (i = 0; i < keywordCount; i++) | ||
711 | { | ||
712 | keyword = keywords[i]; | ||
713 | slen = strlen (keyword); | ||
714 | for (j = 0; j < slen; j++) | ||
715 | { | ||
716 | if ((j == 0) && (keyword[j] == ' ')) | ||
717 | continue; /* skip leading space */ | ||
718 | if (needs_percent (keyword[j])) | ||
719 | { | ||
720 | sprintf (&ret[wpos], "%%%02X", keyword[j]); | ||
721 | wpos += 3; | ||
722 | } | ||
723 | else | ||
724 | { | ||
725 | ret[wpos++] = keyword[j]; | ||
726 | } | ||
727 | } | ||
728 | if (i != keywordCount - 1) | ||
729 | ret[wpos++] = '+'; | ||
730 | } | ||
731 | return ret; | ||
732 | } | ||
733 | |||
734 | /** | ||
735 | * Generate a subspace URI. | ||
736 | */ | ||
737 | static char * | ||
738 | createSubspaceURI (const GNUNET_HashCode * namespace, const char *identifier) | ||
739 | { | ||
740 | size_t n; | ||
741 | char *ret; | ||
742 | GNUNET_EncName ns; | ||
743 | |||
744 | n = | ||
745 | sizeof (GNUNET_EncName) + strlen (GNUNET_ECRS_URI_PREFIX) + | ||
746 | strlen (GNUNET_ECRS_SUBSPACE_INFIX) + 1 + strlen (identifier); | ||
747 | ret = GNUNET_malloc (n); | ||
748 | GNUNET_hash_to_enc (namespace, &ns); | ||
749 | GNUNET_snprintf (ret, n, | ||
750 | "%s%s%s/%s", | ||
751 | GNUNET_ECRS_URI_PREFIX, GNUNET_ECRS_SUBSPACE_INFIX, | ||
752 | (const char *) &ns, identifier); | ||
753 | return ret; | ||
754 | } | ||
755 | |||
756 | /** | ||
757 | * Generate a file URI. | ||
758 | */ | ||
759 | static char * | ||
760 | createFileURI (const GNUNET_EC_FileIdentifier * fi) | ||
761 | { | ||
762 | char *ret; | ||
763 | GNUNET_EncName keyhash; | ||
764 | GNUNET_EncName queryhash; | ||
765 | size_t n; | ||
766 | |||
767 | GNUNET_hash_to_enc (&fi->chk.key, &keyhash); | ||
768 | GNUNET_hash_to_enc (&fi->chk.query, &queryhash); | ||
769 | |||
770 | n = | ||
771 | strlen (GNUNET_ECRS_URI_PREFIX) + 2 * sizeof (GNUNET_EncName) + 8 + 16 + | ||
772 | 32 + strlen (GNUNET_ECRS_FILE_INFIX); | ||
773 | ret = GNUNET_malloc (n); | ||
774 | GNUNET_snprintf (ret, | ||
775 | n, | ||
776 | "%s%s%s.%s.%llu", | ||
777 | GNUNET_ECRS_URI_PREFIX, | ||
778 | GNUNET_ECRS_FILE_INFIX, | ||
779 | (char *) &keyhash, (char *) &queryhash, | ||
780 | GNUNET_ntohll (fi->file_length)); | ||
781 | return ret; | ||
782 | } | ||
783 | |||
784 | #include "bincoder.c" | ||
785 | |||
786 | /** | ||
787 | * Create a (string) location URI from a Location. | ||
788 | */ | ||
789 | static char * | ||
790 | createLocURI (const Location * loc) | ||
791 | { | ||
792 | size_t n; | ||
793 | char *ret; | ||
794 | GNUNET_EncName keyhash; | ||
795 | GNUNET_EncName queryhash; | ||
796 | char *peerId; | ||
797 | char *peerSig; | ||
798 | |||
799 | GNUNET_hash_to_enc (&loc->fi.chk.key, &keyhash); | ||
800 | GNUNET_hash_to_enc (&loc->fi.chk.query, &queryhash); | ||
801 | n = 2148; | ||
802 | peerId = bin2enc (&loc->peer, sizeof (GNUNET_RSA_PublicKey)); | ||
803 | peerSig = bin2enc (&loc->contentSignature, sizeof (GNUNET_RSA_Signature)); | ||
804 | ret = GNUNET_malloc (n); | ||
805 | GNUNET_snprintf (ret, | ||
806 | n, | ||
807 | "%s%s%s.%s.%llu.%s.%s.%u", | ||
808 | GNUNET_ECRS_URI_PREFIX, | ||
809 | GNUNET_ECRS_LOCATION_INFIX, | ||
810 | (char *) &keyhash, | ||
811 | (char *) &queryhash, | ||
812 | GNUNET_ntohll (loc->fi.file_length), | ||
813 | peerId, peerSig, loc->expirationTime); | ||
814 | GNUNET_free (peerSig); | ||
815 | GNUNET_free (peerId); | ||
816 | return ret; | ||
817 | } | ||
818 | |||
819 | /** | ||
820 | * Convert a URI to a UTF-8 String. | ||
821 | */ | ||
822 | char * | ||
823 | GNUNET_ECRS_uri_to_string (const struct GNUNET_ECRS_URI *uri) | ||
824 | { | ||
825 | if (uri == NULL) | ||
826 | { | ||
827 | GNUNET_GE_BREAK (NULL, 0); | ||
828 | return NULL; | ||
829 | } | ||
830 | switch (uri->type) | ||
831 | { | ||
832 | case ksk: | ||
833 | return createKeywordURI (uri->data.ksk.keywords, | ||
834 | uri->data.ksk.keywordCount); | ||
835 | case sks: | ||
836 | return createSubspaceURI (&uri->data.sks.namespace, | ||
837 | uri->data.sks.identifier); | ||
838 | case chk: | ||
839 | return createFileURI (&uri->data.fi); | ||
840 | case loc: | ||
841 | return createLocURI (&uri->data.loc); | ||
842 | default: | ||
843 | GNUNET_GE_BREAK (NULL, 0); | ||
844 | return NULL; | ||
845 | } | ||
846 | } | ||
847 | |||
848 | /** | ||
849 | * Convert keyword URI to a human readable format | ||
850 | * (i.e. the search query that was used in the first place) | ||
851 | */ | ||
852 | char * | ||
853 | GNUNET_ECRS_ksk_uri_to_human_readable_string (const struct GNUNET_ECRS_URI | ||
854 | *uri) | ||
855 | { | ||
856 | size_t n; | ||
857 | char *ret; | ||
858 | unsigned int i; | ||
859 | const char *keyword; | ||
860 | char **keywords; | ||
861 | unsigned int keywordCount; | ||
862 | |||
863 | if ((uri == NULL) || (uri->type != ksk)) | ||
864 | { | ||
865 | GNUNET_GE_BREAK (NULL, 0); | ||
866 | return NULL; | ||
867 | } | ||
868 | keywords = uri->data.ksk.keywords; | ||
869 | keywordCount = uri->data.ksk.keywordCount; | ||
870 | n = keywordCount + 1; | ||
871 | for (i = 0; i < keywordCount; i++) | ||
872 | { | ||
873 | keyword = keywords[i]; | ||
874 | n += strlen (keyword) - 1; | ||
875 | if (NULL != strstr (&keyword[1], " ")) | ||
876 | n += 2; | ||
877 | if (keyword[0] == '+') | ||
878 | n++; | ||
879 | } | ||
880 | ret = GNUNET_malloc (n); | ||
881 | strcpy (ret, ""); | ||
882 | for (i = 0; i < keywordCount; i++) | ||
883 | { | ||
884 | keyword = keywords[i]; | ||
885 | if (NULL != strstr (&keyword[1], " ")) | ||
886 | { | ||
887 | strcat (ret, "\""); | ||
888 | if (keyword[0] == '+') | ||
889 | strcat (ret, keyword); | ||
890 | else | ||
891 | strcat (ret, &keyword[1]); | ||
892 | strcat (ret, "\""); | ||
893 | } | ||
894 | else | ||
895 | { | ||
896 | if (keyword[0] == '+') | ||
897 | strcat (ret, keyword); | ||
898 | else | ||
899 | strcat (ret, &keyword[1]); | ||
900 | } | ||
901 | strcat (ret, " "); | ||
902 | } | ||
903 | return ret; | ||
904 | } | ||
905 | |||
906 | /** | ||
907 | * Given a keyword with %-encoding (and possibly quotes to protect | ||
908 | * spaces), return a copy of the keyword without %-encoding and | ||
909 | * without double-quotes (%22). Also, add a space at the beginning | ||
910 | * if there is not a '+'. | ||
911 | */ | ||
912 | static char * | ||
913 | percent_decode_keyword (const char *in) | ||
914 | { | ||
915 | char *out; | ||
916 | char *ret; | ||
917 | unsigned int rpos; | ||
918 | unsigned int wpos; | ||
919 | unsigned int hx; | ||
920 | |||
921 | out = GNUNET_strdup (in); | ||
922 | rpos = 0; | ||
923 | wpos = 0; | ||
924 | while (out[rpos] != '\0') | ||
925 | { | ||
926 | if (out[rpos] == '%') | ||
927 | { | ||
928 | if (1 != sscanf (&out[rpos + 1], "%2X", &hx)) | ||
929 | { | ||
930 | GNUNET_free (out); | ||
931 | return NULL; | ||
932 | } | ||
933 | rpos += 3; | ||
934 | if (hx == '"') | ||
935 | continue; /* skip double quote */ | ||
936 | out[wpos++] = (char) hx; | ||
937 | } | ||
938 | else | ||
939 | { | ||
940 | out[wpos++] = out[rpos++]; | ||
941 | } | ||
942 | } | ||
943 | out[wpos] = '\0'; | ||
944 | if (out[0] == '+') | ||
945 | { | ||
946 | ret = GNUNET_strdup (out); | ||
947 | } | ||
948 | else | ||
949 | { | ||
950 | /* need to prefix with space */ | ||
951 | ret = GNUNET_malloc (strlen (out) + 2); | ||
952 | strcpy (ret, " "); | ||
953 | strcat (ret, out); | ||
954 | } | ||
955 | GNUNET_free (out); | ||
956 | return ret; | ||
957 | } | ||
958 | |||
959 | /** | ||
960 | * Parses an ECRS search URI. | ||
961 | * | ||
962 | * @param uri an uri string | ||
963 | * @param keyword will be set to an array with the keywords | ||
964 | * @return GNUNET_SYSERR if this is not a search URI, otherwise | ||
965 | * the number of keywords placed in the array | ||
966 | */ | ||
967 | static int | ||
968 | parseKeywordURI (struct GNUNET_GE_Context *ectx, const char *uri, | ||
969 | char ***keywords) | ||
970 | { | ||
971 | unsigned int pos; | ||
972 | int ret; | ||
973 | int iret; | ||
974 | int i; | ||
975 | size_t slen; | ||
976 | char *dup; | ||
977 | int saw_quote; | ||
978 | |||
979 | GNUNET_GE_ASSERT (ectx, uri != NULL); | ||
980 | |||
981 | slen = strlen (uri); | ||
982 | pos = strlen (GNUNET_ECRS_URI_PREFIX); | ||
983 | |||
984 | if (0 != strncmp (uri, GNUNET_ECRS_URI_PREFIX, pos)) | ||
985 | return GNUNET_SYSERR; | ||
986 | if (0 != | ||
987 | strncmp (&uri[pos], GNUNET_ECRS_SEARCH_INFIX, | ||
988 | strlen (GNUNET_ECRS_SEARCH_INFIX))) | ||
989 | return GNUNET_SYSERR; | ||
990 | pos += strlen (GNUNET_ECRS_SEARCH_INFIX); | ||
991 | if (slen == pos) | ||
992 | { | ||
993 | /* no keywords */ | ||
994 | (*keywords) = NULL; | ||
995 | return 0; | ||
996 | } | ||
997 | if ((uri[slen - 1] == '+') || (uri[pos] == '+')) | ||
998 | return GNUNET_SYSERR; /* no keywords / malformed */ | ||
999 | |||
1000 | ret = 1; | ||
1001 | saw_quote = 0; | ||
1002 | for (i = pos; i < slen; i++) | ||
1003 | { | ||
1004 | if ((uri[i] == '%') && (&uri[i] == strstr (&uri[i], "%22"))) | ||
1005 | { | ||
1006 | saw_quote = (saw_quote + 1) % 2; | ||
1007 | i += 3; | ||
1008 | continue; | ||
1009 | } | ||
1010 | if ((uri[i] == '+') && (saw_quote == 0)) | ||
1011 | { | ||
1012 | ret++; | ||
1013 | if (uri[i - 1] == '+') | ||
1014 | return GNUNET_SYSERR; /* "++" not allowed */ | ||
1015 | } | ||
1016 | } | ||
1017 | if (saw_quote == 1) | ||
1018 | return GNUNET_SYSERR; /* quotes not balanced */ | ||
1019 | iret = ret; | ||
1020 | dup = GNUNET_strdup (uri); | ||
1021 | (*keywords) = GNUNET_malloc (ret * sizeof (char *)); | ||
1022 | for (i = 0; i < ret; i++) | ||
1023 | (*keywords)[i] = NULL; | ||
1024 | for (i = slen - 1; i >= pos; i--) | ||
1025 | { | ||
1026 | if ((uri[i] == '%') && (&uri[i] == strstr (&uri[i], "%22"))) | ||
1027 | { | ||
1028 | saw_quote = (saw_quote + 1) % 2; | ||
1029 | i += 3; | ||
1030 | continue; | ||
1031 | } | ||
1032 | if ((dup[i] == '+') && (saw_quote == 0)) | ||
1033 | { | ||
1034 | (*keywords)[--ret] = percent_decode_keyword (&dup[i + 1]); | ||
1035 | if (NULL == (*keywords)[ret]) | ||
1036 | goto CLEANUP; | ||
1037 | dup[i] = '\0'; | ||
1038 | } | ||
1039 | } | ||
1040 | (*keywords)[--ret] = percent_decode_keyword (&dup[pos]); | ||
1041 | if (NULL == (*keywords)[ret]) | ||
1042 | goto CLEANUP; | ||
1043 | GNUNET_GE_ASSERT (ectx, ret == 0); | ||
1044 | GNUNET_free (dup); | ||
1045 | return iret; | ||
1046 | CLEANUP: | ||
1047 | for (i = 0; i < ret; i++) | ||
1048 | GNUNET_free_non_null ((*keywords)[i]); | ||
1049 | GNUNET_free (*keywords); | ||
1050 | *keywords = NULL; | ||
1051 | GNUNET_free (dup); | ||
1052 | return GNUNET_SYSERR; | ||
1053 | } | ||
1054 | |||
1055 | /** | ||
1056 | * Parses an AFS namespace / subspace identifier URI. | ||
1057 | * | ||
1058 | * @param uri an uri string | ||
1059 | * @param namespace set to the namespace ID | ||
1060 | * @param identifier set to the ID in the namespace | ||
1061 | * @return GNUNET_OK on success, GNUNET_SYSERR if this is not a namespace URI | ||
1062 | */ | ||
1063 | static int | ||
1064 | parseSubspaceURI (struct GNUNET_GE_Context *ectx, | ||
1065 | const char *uri, | ||
1066 | GNUNET_HashCode * namespace, char **identifier) | ||
1067 | { | ||
1068 | unsigned int pos; | ||
1069 | size_t slen; | ||
1070 | char *up; | ||
1071 | |||
1072 | GNUNET_GE_ASSERT (ectx, uri != NULL); | ||
1073 | |||
1074 | slen = strlen (uri); | ||
1075 | pos = strlen (GNUNET_ECRS_URI_PREFIX); | ||
1076 | |||
1077 | if (0 != strncmp (uri, GNUNET_ECRS_URI_PREFIX, pos)) | ||
1078 | return GNUNET_SYSERR; | ||
1079 | if (0 != strncmp (&uri[pos], | ||
1080 | GNUNET_ECRS_SUBSPACE_INFIX, | ||
1081 | strlen (GNUNET_ECRS_SUBSPACE_INFIX))) | ||
1082 | return GNUNET_SYSERR; | ||
1083 | pos += strlen (GNUNET_ECRS_SUBSPACE_INFIX); | ||
1084 | if ((slen < pos + sizeof (GNUNET_EncName) + 1) || | ||
1085 | (!((uri[pos + sizeof (GNUNET_EncName) - 1] == '/') || | ||
1086 | (uri[pos + sizeof (GNUNET_EncName) - 1] == '\\')))) | ||
1087 | return GNUNET_SYSERR; | ||
1088 | |||
1089 | up = GNUNET_strdup (uri); | ||
1090 | up[pos + sizeof (GNUNET_EncName) - 1] = '\0'; | ||
1091 | if ((GNUNET_OK != GNUNET_enc_to_hash (&up[pos], namespace))) | ||
1092 | { | ||
1093 | GNUNET_free (up); | ||
1094 | return GNUNET_SYSERR; | ||
1095 | } | ||
1096 | *identifier = GNUNET_strdup (&up[pos + sizeof (GNUNET_EncName)]); | ||
1097 | GNUNET_free (up); | ||
1098 | return GNUNET_OK; | ||
1099 | } | ||
1100 | |||
1101 | /** | ||
1102 | * Parses an URI that identifies a file | ||
1103 | * | ||
1104 | * @param uri an uri string | ||
1105 | * @param fi the file identifier | ||
1106 | * @return GNUNET_OK on success, GNUNET_SYSERR if this is not a file URI | ||
1107 | */ | ||
1108 | static int | ||
1109 | parseFileURI (struct GNUNET_GE_Context *ectx, const char *uri, | ||
1110 | GNUNET_EC_FileIdentifier * fi) | ||
1111 | { | ||
1112 | unsigned int pos; | ||
1113 | size_t slen; | ||
1114 | char *dup; | ||
1115 | |||
1116 | GNUNET_GE_ASSERT (ectx, uri != NULL); | ||
1117 | |||
1118 | slen = strlen (uri); | ||
1119 | pos = strlen (GNUNET_ECRS_URI_PREFIX); | ||
1120 | |||
1121 | if (0 != strncmp (uri, GNUNET_ECRS_URI_PREFIX, pos)) | ||
1122 | return GNUNET_SYSERR; | ||
1123 | if (0 != | ||
1124 | strncmp (&uri[pos], GNUNET_ECRS_FILE_INFIX, | ||
1125 | strlen (GNUNET_ECRS_FILE_INFIX))) | ||
1126 | return GNUNET_SYSERR; | ||
1127 | pos += strlen (GNUNET_ECRS_FILE_INFIX); | ||
1128 | if ((slen < pos + 2 * sizeof (GNUNET_EncName) + 1) || | ||
1129 | (uri[pos + sizeof (GNUNET_EncName) - 1] != '.') || | ||
1130 | (uri[pos + sizeof (GNUNET_EncName) * 2 - 1] != '.')) | ||
1131 | return GNUNET_SYSERR; | ||
1132 | |||
1133 | dup = GNUNET_strdup (uri); | ||
1134 | dup[pos + sizeof (GNUNET_EncName) - 1] = '\0'; | ||
1135 | dup[pos + sizeof (GNUNET_EncName) * 2 - 1] = '\0'; | ||
1136 | if ((GNUNET_OK != GNUNET_enc_to_hash (&dup[pos], | ||
1137 | &fi->chk.key)) || | ||
1138 | (GNUNET_OK != GNUNET_enc_to_hash (&dup[pos + sizeof (GNUNET_EncName)], | ||
1139 | &fi->chk.query)) || | ||
1140 | (1 != SSCANF (&dup[pos + sizeof (GNUNET_EncName) * 2], | ||
1141 | "%llu", &fi->file_length))) | ||
1142 | { | ||
1143 | GNUNET_free (dup); | ||
1144 | return GNUNET_SYSERR; | ||
1145 | } | ||
1146 | GNUNET_free (dup); | ||
1147 | fi->file_length = GNUNET_htonll (fi->file_length); | ||
1148 | return GNUNET_OK; | ||
1149 | } | ||
1150 | |||
1151 | /** | ||
1152 | * Parses an URI that identifies a location (and file). | ||
1153 | * Also verifies validity of the location URI. | ||
1154 | * | ||
1155 | * @param uri an uri string | ||
1156 | * @param loc where to store the location | ||
1157 | * @return GNUNET_OK on success, GNUNET_SYSERR if this is not a file URI | ||
1158 | */ | ||
1159 | static int | ||
1160 | parseLocationURI (struct GNUNET_GE_Context *ectx, const char *uri, | ||
1161 | Location * loc) | ||
1162 | { | ||
1163 | unsigned int pos; | ||
1164 | unsigned int npos; | ||
1165 | int ret; | ||
1166 | size_t slen; | ||
1167 | char *dup; | ||
1168 | char *addr; | ||
1169 | |||
1170 | |||
1171 | GNUNET_GE_ASSERT (ectx, uri != NULL); | ||
1172 | addr = NULL; | ||
1173 | slen = strlen (uri); | ||
1174 | pos = strlen (GNUNET_ECRS_URI_PREFIX); | ||
1175 | |||
1176 | if (0 != strncmp (uri, GNUNET_ECRS_URI_PREFIX, pos)) | ||
1177 | return GNUNET_SYSERR; | ||
1178 | if (0 != strncmp (&uri[pos], | ||
1179 | GNUNET_ECRS_LOCATION_INFIX, | ||
1180 | strlen (GNUNET_ECRS_LOCATION_INFIX))) | ||
1181 | return GNUNET_SYSERR; | ||
1182 | pos += strlen (GNUNET_ECRS_LOCATION_INFIX); | ||
1183 | if ((slen < pos + 2 * sizeof (GNUNET_EncName) + 1) || | ||
1184 | (uri[pos + sizeof (GNUNET_EncName) - 1] != '.') || | ||
1185 | (uri[pos + sizeof (GNUNET_EncName) * 2 - 1] != '.')) | ||
1186 | return GNUNET_SYSERR; | ||
1187 | |||
1188 | dup = GNUNET_strdup (uri); | ||
1189 | dup[pos + sizeof (GNUNET_EncName) - 1] = '\0'; | ||
1190 | dup[pos + sizeof (GNUNET_EncName) * 2 - 1] = '\0'; | ||
1191 | npos = pos + sizeof (GNUNET_EncName) * 2; | ||
1192 | while ((uri[npos] != '\0') && (uri[npos] != '.')) | ||
1193 | npos++; | ||
1194 | if (dup[npos] == '\0') | ||
1195 | goto ERR; | ||
1196 | dup[npos++] = '\0'; | ||
1197 | if ((GNUNET_OK != GNUNET_enc_to_hash (&dup[pos], | ||
1198 | &loc->fi.chk.key)) || | ||
1199 | (GNUNET_OK != GNUNET_enc_to_hash (&dup[pos + sizeof (GNUNET_EncName)], | ||
1200 | &loc->fi.chk.query)) || | ||
1201 | (1 != SSCANF (&dup[pos + sizeof (GNUNET_EncName) * 2], | ||
1202 | "%llu", &loc->fi.file_length))) | ||
1203 | goto ERR; | ||
1204 | loc->fi.file_length = GNUNET_htonll (loc->fi.file_length); | ||
1205 | ret = enc2bin (&dup[npos], &loc->peer, sizeof (GNUNET_RSA_PublicKey)); | ||
1206 | if (ret == -1) | ||
1207 | goto ERR; | ||
1208 | npos += ret; | ||
1209 | if (dup[npos++] != '.') | ||
1210 | goto ERR; | ||
1211 | ret = | ||
1212 | enc2bin (&dup[npos], &loc->contentSignature, | ||
1213 | sizeof (GNUNET_RSA_Signature)); | ||
1214 | if (ret == -1) | ||
1215 | goto ERR; | ||
1216 | npos += ret; | ||
1217 | if (dup[npos++] != '.') | ||
1218 | goto ERR; | ||
1219 | if (1 != SSCANF (&dup[npos], "%u", &loc->expirationTime)) | ||
1220 | goto ERR; | ||
1221 | /* Finally: verify sigs! */ | ||
1222 | if (GNUNET_OK != GNUNET_RSA_verify (&loc->fi, | ||
1223 | sizeof (GNUNET_EC_FileIdentifier) + | ||
1224 | sizeof (GNUNET_PeerIdentity) + | ||
1225 | sizeof (GNUNET_Int32Time), | ||
1226 | &loc->contentSignature, &loc->peer)) | ||
1227 | goto ERR; | ||
1228 | GNUNET_free (dup); | ||
1229 | return GNUNET_OK; | ||
1230 | ERR: | ||
1231 | GNUNET_free (dup); | ||
1232 | GNUNET_free_non_null (addr); | ||
1233 | return GNUNET_SYSERR; | ||
1234 | } | ||
1235 | |||
1236 | /** | ||
1237 | * Convert a UTF-8 String to a URI. | ||
1238 | */ | ||
1239 | URI * | ||
1240 | GNUNET_ECRS_string_to_uri (struct GNUNET_GE_Context * ectx, const char *uri) | ||
1241 | { | ||
1242 | URI *ret; | ||
1243 | int len; | ||
1244 | |||
1245 | ret = GNUNET_malloc (sizeof (URI)); | ||
1246 | if (GNUNET_OK == parseFileURI (ectx, uri, &ret->data.fi)) | ||
1247 | { | ||
1248 | ret->type = chk; | ||
1249 | return ret; | ||
1250 | } | ||
1251 | if (GNUNET_OK == parseSubspaceURI (ectx, | ||
1252 | uri, | ||
1253 | &ret->data.sks.namespace, | ||
1254 | &ret->data.sks.identifier)) | ||
1255 | { | ||
1256 | ret->type = sks; | ||
1257 | return ret; | ||
1258 | } | ||
1259 | if (GNUNET_OK == parseLocationURI (ectx, uri, &ret->data.loc)) | ||
1260 | { | ||
1261 | ret->type = loc; | ||
1262 | return ret; | ||
1263 | } | ||
1264 | len = parseKeywordURI (ectx, uri, &ret->data.ksk.keywords); | ||
1265 | if (len < 0) | ||
1266 | { | ||
1267 | GNUNET_free (ret); | ||
1268 | return NULL; | ||
1269 | } | ||
1270 | ret->type = ksk; | ||
1271 | ret->data.ksk.keywordCount = len; | ||
1272 | return ret; | ||
1273 | } | ||
1274 | |||
1275 | |||
1276 | |||
1277 | /** | ||
1278 | * Construct a location URI. | ||
1279 | * | ||
1280 | * @param baseURI content offered by the sender | ||
1281 | * @param sender identity of the peer with the content | ||
1282 | * @param expiration_time how long will the content be offered? | ||
1283 | * @param proto transport protocol to reach the peer | ||
1284 | * @param sas sender address size (for HELLO) | ||
1285 | * @param address sas bytes of address information | ||
1286 | * @param signer function to call for obtaining | ||
1287 | * RSA signatures for "sender". | ||
1288 | * @return the location URI | ||
1289 | */ | ||
1290 | struct GNUNET_ECRS_URI * | ||
1291 | GNUNET_ECRS_location_to_uri (const struct GNUNET_ECRS_URI *baseUri, | ||
1292 | const GNUNET_RSA_PublicKey * sender, | ||
1293 | GNUNET_Int32Time expirationTime, | ||
1294 | GNUNET_ECRS_SignFunction signer, | ||
1295 | void *signer_cls) | ||
1296 | { | ||
1297 | struct GNUNET_ECRS_URI *uri; | ||
1298 | |||
1299 | if (baseUri->type != chk) | ||
1300 | return NULL; | ||
1301 | |||
1302 | uri = GNUNET_malloc (sizeof (struct GNUNET_ECRS_URI)); | ||
1303 | uri->type = loc; | ||
1304 | uri->data.loc.fi = baseUri->data.fi; | ||
1305 | uri->data.loc.peer = *sender; | ||
1306 | uri->data.loc.expirationTime = expirationTime; | ||
1307 | signer (signer_cls, | ||
1308 | sizeof (GNUNET_EC_FileIdentifier) + | ||
1309 | sizeof (GNUNET_PeerIdentity) + | ||
1310 | sizeof (GNUNET_Int32Time), | ||
1311 | &uri->data.loc.fi, &uri->data.loc.contentSignature); | ||
1312 | return uri; | ||
1313 | } | ||
1314 | |||
1315 | #endif | ||
1316 | |||
1317 | /* end of uri.c */ | ||