- clean up the receive switch case
[oweals/gnunet.git] / src / fs / fs_namespace.c
1 /*
2      This file is part of GNUnet
3      (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 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 3, 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_namespace.c
23  * @brief create and destroy namespaces
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_constants.h"
28 #include "gnunet_signatures.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_fs_service.h"
31 #include "fs_api.h"
32
33 #define DEBUG_NAMESPACE GNUNET_EXTRA_LOGGING
34
35
36 /**
37  * Maximum legal size for an sblock.
38  */
39 #define MAX_SBLOCK_SIZE (60 * 1024)
40
41 /**
42  * Maximum legal size for an nblock.
43  */
44 #define MAX_NBLOCK_SIZE (60 * 1024)
45
46
47 /**
48  * Return the name of the directory in which we store
49  * our local namespaces (or rather, their public keys).
50  *
51  * @param h global fs handle
52  * @return NULL on error, otherwise the name of the directory
53  */
54 static char *
55 get_namespace_directory (struct GNUNET_FS_Handle *h)
56 {
57   char *dn;
58
59   if (GNUNET_OK !=
60       GNUNET_CONFIGURATION_get_value_filename (h->cfg, "FS", "IDENTITY_DIR",
61                                                &dn))
62   {
63     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
64                 _("Configuration fails to specify `%s' in section `%s'\n"),
65                 "IDENTITY_DIR", "fs");
66     return NULL;
67   }
68   return dn;
69 }
70
71
72 /**
73  * Return the name of the directory in which we store
74  * the update information graph for the given local namespace.
75  *
76  * @param ns namespace handle
77  * @return NULL on error, otherwise the name of the directory
78  */
79 static char *
80 get_update_information_directory (struct GNUNET_FS_Namespace *ns)
81 {
82   char *dn;
83   char *ret;
84
85   if (GNUNET_OK !=
86       GNUNET_CONFIGURATION_get_value_filename (ns->h->cfg, "FS", "UPDATE_DIR",
87                                                &dn))
88   {
89     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
90                 _("Configuration fails to specify `%s' in section `%s'\n"),
91                 "UPDATE_DIR", "fs");
92     return NULL;
93   }
94   GNUNET_asprintf (&ret, "%s%s%s", dn, DIR_SEPARATOR_STR, ns->name);
95   GNUNET_free (dn);
96   return ret;
97 }
98
99
100 /**
101  * Write the namespace update node graph to a file.
102  *
103  * @param ns namespace to dump
104  */
105 static void
106 write_update_information_graph (struct GNUNET_FS_Namespace *ns)
107 {
108   char *fn;
109   struct GNUNET_BIO_WriteHandle *wh;
110   unsigned int i;
111   struct NamespaceUpdateNode *n;
112   char *uris;
113
114   fn = get_update_information_directory (ns);
115   wh = GNUNET_BIO_write_open (fn);
116   if (wh == NULL)
117   {
118     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
119                 _("Failed to open `%s' for writing: %s\n"), STRERROR (errno));
120     GNUNET_free (fn);
121     return;
122   }
123   if (GNUNET_OK != GNUNET_BIO_write_int32 (wh, ns->update_node_count))
124     goto END;
125   for (i = 0; i < ns->update_node_count; i++)
126   {
127     n = ns->update_nodes[i];
128     uris = GNUNET_FS_uri_to_string (n->uri);
129     if ((GNUNET_OK != GNUNET_BIO_write_string (wh, n->id)) ||
130         (GNUNET_OK != GNUNET_BIO_write_meta_data (wh, n->md)) ||
131         (GNUNET_OK != GNUNET_BIO_write_string (wh, n->update)) ||
132         (GNUNET_OK != GNUNET_BIO_write_string (wh, uris)))
133     {
134       GNUNET_free (uris);
135       break;
136     }
137     GNUNET_free (uris);
138   }
139 END:
140   if (GNUNET_OK != GNUNET_BIO_write_close (wh))
141     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to write `%s': %s\n"),
142                 STRERROR (errno));
143   GNUNET_free (fn);
144 }
145
146
147 /**
148  * Read the namespace update node graph from a file.
149  *
150  * @param ns namespace to read
151  */
152 static void
153 read_update_information_graph (struct GNUNET_FS_Namespace *ns)
154 {
155   char *fn;
156   struct GNUNET_BIO_ReadHandle *rh;
157   unsigned int i;
158   struct NamespaceUpdateNode *n;
159   char *uris;
160   uint32_t count;
161   char *emsg;
162
163   fn = get_update_information_directory (ns);
164   if (GNUNET_YES != GNUNET_DISK_file_test (fn))
165   {
166     GNUNET_free (fn);
167     return;
168   }
169   rh = GNUNET_BIO_read_open (fn);
170   if (rh == NULL)
171   {
172     GNUNET_free (fn);
173     return;
174   }
175   if (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &count))
176   {
177     GNUNET_break (0);
178     goto END;
179   }
180   if (count > 1024 * 1024)
181   {
182     GNUNET_break (0);
183     goto END;
184   }
185   if (count == 0)
186   {
187     GNUNET_break (GNUNET_OK == GNUNET_BIO_read_close (rh, NULL));
188     GNUNET_free (fn);
189     return;
190   }
191   ns->update_nodes =
192       GNUNET_malloc (count * sizeof (struct NamespaceUpdateNode *));
193
194   for (i = 0; i < count; i++)
195   {
196     n = GNUNET_malloc (sizeof (struct NamespaceUpdateNode));
197     if ((GNUNET_OK != GNUNET_BIO_read_string (rh, "identifier", &n->id, 1024))
198         || (GNUNET_OK != GNUNET_BIO_read_meta_data (rh, "meta", &n->md)) ||
199         (GNUNET_OK !=
200          GNUNET_BIO_read_string (rh, "update-id", &n->update, 1024)) ||
201         (GNUNET_OK != GNUNET_BIO_read_string (rh, "uri", &uris, 1024 * 2)))
202     {
203       GNUNET_break (0);
204       GNUNET_free_non_null (n->id);
205       GNUNET_free_non_null (n->update);
206       if (n->md != NULL)
207         GNUNET_CONTAINER_meta_data_destroy (n->md);
208       GNUNET_free (n);
209       break;
210     }
211     n->uri = GNUNET_FS_uri_parse (uris, &emsg);
212     GNUNET_free (uris);
213     if (n->uri == NULL)
214     {
215       GNUNET_break (0);
216       GNUNET_free (emsg);
217       GNUNET_free (n->id);
218       GNUNET_free_non_null (n->update);
219       GNUNET_CONTAINER_meta_data_destroy (n->md);
220       GNUNET_free (n);
221       break;
222     }
223     ns->update_nodes[i] = n;
224   }
225   ns->update_node_count = i;
226 END:
227   if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))
228   {
229     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to write `%s': %s\n"), emsg);
230     GNUNET_free (emsg);
231   }
232   GNUNET_free (fn);
233 }
234
235
236 /**
237  * Context for advertising a namespace.
238  */
239 struct AdvertisementContext
240 {
241   /**
242    * Function to call with the result.
243    */
244   GNUNET_FS_PublishContinuation cont;
245
246   /**
247    * Closure for cont.
248    */
249   void *cont_cls;
250
251   /**
252    * Datastore handle.
253    */
254   struct GNUNET_DATASTORE_Handle *dsh;
255
256   /**
257    * Our KSK URI.
258    */
259   struct GNUNET_FS_Uri *ksk_uri;
260
261   /**
262    * Plaintext.
263    */
264   char *pt;
265
266   /**
267    * NBlock to sign and store.
268    */
269   struct NBlock *nb;
270
271   /**
272    * The namespace.
273    */
274   struct GNUNET_FS_Namespace *ns;
275
276   /**
277    * Block options.
278    */
279   struct GNUNET_FS_BlockOptions bo;
280
281   /**
282    * Number of bytes of plaintext.
283    */
284   size_t pt_size;
285
286   /**
287    * Current keyword offset.
288    */
289   unsigned int pos;
290 };
291
292
293 /**
294  * Disconnect from the datastore.
295  *
296  * @param cls datastore handle
297  * @param tc scheduler context
298  */
299 static void
300 do_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
301 {
302   struct GNUNET_DATASTORE_Handle *dsh = cls;
303
304   GNUNET_DATASTORE_disconnect (dsh, GNUNET_NO);
305 }
306
307
308 /**
309  * Continuation called to notify client about result of the
310  * operation.
311  *
312  * @param cls closure (our struct AdvertismentContext)
313  * @param success GNUNET_SYSERR on failure
314  * @param min_expiration minimum expiration time required for content to be stored
315  * @param msg NULL on success, otherwise an error message
316  */
317 static void
318 advertisement_cont (void *cls, int success, 
319                     struct GNUNET_TIME_Absolute min_expiration,
320                     const char *msg)
321 {
322   struct AdvertisementContext *ac = cls;
323   const char *keyword;
324   GNUNET_HashCode key;
325   GNUNET_HashCode query;
326   struct GNUNET_CRYPTO_AesSessionKey skey;
327   struct GNUNET_CRYPTO_AesInitializationVector iv;
328   struct GNUNET_CRYPTO_RsaPrivateKey *pk;
329
330   if (GNUNET_OK != success)
331   {
332     /* error! */
333     GNUNET_SCHEDULER_add_continuation (&do_disconnect, ac->dsh,
334                                        GNUNET_SCHEDULER_REASON_PREREQ_DONE);
335     if (msg == NULL)
336     {
337       GNUNET_break (0);
338       msg = _("Unknown error");
339     }
340     if (ac->cont != NULL)
341       ac->cont (ac->cont_cls, NULL, msg);
342     GNUNET_FS_uri_destroy (ac->ksk_uri);
343     GNUNET_free (ac->pt);
344     GNUNET_free (ac->nb);
345     GNUNET_FS_namespace_delete (ac->ns, GNUNET_NO);
346     GNUNET_free (ac);
347     return;
348   }
349   if (ac->pos == ac->ksk_uri->data.ksk.keywordCount)
350   {
351     /* done! */
352     GNUNET_SCHEDULER_add_continuation (&do_disconnect, ac->dsh,
353                                        GNUNET_SCHEDULER_REASON_PREREQ_DONE);
354     if (ac->cont != NULL)
355       ac->cont (ac->cont_cls, ac->ksk_uri, NULL);
356     GNUNET_FS_uri_destroy (ac->ksk_uri);
357     GNUNET_free (ac->pt);
358     GNUNET_free (ac->nb);
359     GNUNET_FS_namespace_delete (ac->ns, GNUNET_NO);
360     GNUNET_free (ac);
361     return;
362   }
363   keyword = ac->ksk_uri->data.ksk.keywords[ac->pos++];
364   /* first character of keyword indicates if it is
365    * mandatory or not -- ignore for hashing */
366   GNUNET_CRYPTO_hash (&keyword[1], strlen (&keyword[1]), &key);
367   GNUNET_CRYPTO_hash_to_aes_key (&key, &skey, &iv);
368   GNUNET_CRYPTO_aes_encrypt (ac->pt, ac->pt_size, &skey, &iv, &ac->nb[1]);
369   GNUNET_break (GNUNET_OK ==
370                 GNUNET_CRYPTO_rsa_sign (ac->ns->key, &ac->nb->ns_purpose,
371                                         &ac->nb->ns_signature));
372   pk = GNUNET_CRYPTO_rsa_key_create_from_hash (&key);
373   GNUNET_assert (pk != NULL);
374   GNUNET_CRYPTO_rsa_key_get_public (pk, &ac->nb->keyspace);
375   GNUNET_CRYPTO_hash (&ac->nb->keyspace,
376                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
377                       &query);
378   GNUNET_break (GNUNET_OK ==
379                 GNUNET_CRYPTO_rsa_sign (pk, &ac->nb->ksk_purpose,
380                                         &ac->nb->ksk_signature));
381   GNUNET_CRYPTO_rsa_key_free (pk);
382   GNUNET_DATASTORE_put (ac->dsh, 0 /* no reservation */ ,
383                         &query, ac->pt_size + sizeof (struct NBlock), ac->nb,
384                         GNUNET_BLOCK_TYPE_FS_NBLOCK, ac->bo.content_priority,
385                         ac->bo.anonymity_level, ac->bo.replication_level,
386                         ac->bo.expiration_time, -2, 1,
387                         GNUNET_CONSTANTS_SERVICE_TIMEOUT, &advertisement_cont,
388                         ac);
389 }
390
391
392 /**
393  * Publish an advertismement for a namespace.
394  *
395  * @param h handle to the file sharing subsystem
396  * @param ksk_uri keywords to use for advertisment
397  * @param namespace handle for the namespace that should be advertised
398  * @param meta meta-data for the namespace advertisement
399  * @param bo block options
400  * @param rootEntry name of the root of the namespace
401  * @param cont continuation
402  * @param cont_cls closure for cont
403  */
404 void
405 GNUNET_FS_namespace_advertise (struct GNUNET_FS_Handle *h,
406                                struct GNUNET_FS_Uri *ksk_uri,
407                                struct GNUNET_FS_Namespace *namespace,
408                                const struct GNUNET_CONTAINER_MetaData *meta,
409                                const struct GNUNET_FS_BlockOptions *bo,
410                                const char *rootEntry,
411                                GNUNET_FS_PublishContinuation cont,
412                                void *cont_cls)
413 {
414   size_t reslen;
415   size_t size;
416   ssize_t mdsize;
417   struct NBlock *nb;
418   char *mdst;
419   struct GNUNET_DATASTORE_Handle *dsh;
420   struct AdvertisementContext *ctx;
421   char *pt;
422
423   /* create advertisements */
424   mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta);
425   if (-1 == mdsize)
426   {
427     cont (cont_cls, NULL, _("Failed to serialize meta data"));
428     return;
429   }
430   reslen = strlen (rootEntry) + 1;
431   size = mdsize + sizeof (struct NBlock) + reslen;
432   if (size > MAX_NBLOCK_SIZE)
433   {
434     size = MAX_NBLOCK_SIZE;
435     mdsize = size - sizeof (struct NBlock) - reslen;
436   }
437
438   pt = GNUNET_malloc (mdsize + reslen);
439   memcpy (pt, rootEntry, reslen);
440   mdst = &pt[reslen];
441   mdsize =
442       GNUNET_CONTAINER_meta_data_serialize (meta, &mdst, mdsize,
443                                             GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
444   if (mdsize == -1)
445   {
446     GNUNET_break (0);
447     GNUNET_free (pt);
448     cont (cont_cls, NULL, _("Failed to serialize meta data"));
449     return;
450   }
451   size = mdsize + sizeof (struct NBlock) + reslen;
452   nb = GNUNET_malloc (size);
453   GNUNET_CRYPTO_rsa_key_get_public (namespace->key, &nb->subspace);
454   nb->ns_purpose.size =
455       htonl (mdsize + reslen +
456              sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
457              sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
458   nb->ns_purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK);
459   nb->ksk_purpose.size =
460       htonl (size - sizeof (struct GNUNET_CRYPTO_RsaSignature));
461   nb->ksk_purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK_KSIG);
462   dsh = GNUNET_DATASTORE_connect (h->cfg);
463   if (NULL == dsh)
464   {
465     GNUNET_free (nb);
466     GNUNET_free (pt);
467     cont (cont_cls, NULL, _("Failed to connect to datastore service"));
468     return;
469   }
470   ctx = GNUNET_malloc (sizeof (struct AdvertisementContext));
471   ctx->cont = cont;
472   ctx->cont_cls = cont_cls;
473   ctx->dsh = dsh;
474   ctx->ksk_uri = GNUNET_FS_uri_dup (ksk_uri);
475   ctx->nb = nb;
476   ctx->pt = pt;
477   ctx->pt_size = mdsize + reslen;
478   ctx->ns = namespace;
479   ctx->ns->rc++;
480   ctx->bo = *bo;
481   advertisement_cont (ctx, GNUNET_OK, GNUNET_TIME_UNIT_ZERO_ABS, NULL);
482 }
483
484
485 /**
486  * Create a namespace with the given name; if one already
487  * exists, return a handle to the existing namespace.
488  *
489  * @param h handle to the file sharing subsystem
490  * @param name name to use for the namespace
491  * @return handle to the namespace, NULL on error
492  */
493 struct GNUNET_FS_Namespace *
494 GNUNET_FS_namespace_create (struct GNUNET_FS_Handle *h, const char *name)
495 {
496   char *dn;
497   char *fn;
498   struct GNUNET_FS_Namespace *ret;
499
500   dn = get_namespace_directory (h);
501   GNUNET_asprintf (&fn, "%s%s%s", dn, DIR_SEPARATOR_STR, name);
502   GNUNET_free (dn);
503   ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Namespace));
504   ret->h = h;
505   ret->rc = 1;
506   ret->key = GNUNET_CRYPTO_rsa_key_create_from_file (fn);
507   if (ret->key == NULL)
508   {
509     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
510                 _("Failed to create or read private key for namespace `%s'\n"),
511                 name);
512     GNUNET_free (ret);
513     GNUNET_free (fn);
514     return NULL;
515   }
516   ret->name = GNUNET_strdup (name);
517   ret->filename = fn;
518   return ret;
519 }
520
521
522 /**
523  * Delete a namespace handle.  Can be used for a clean shutdown (free
524  * memory) or also to freeze the namespace to prevent further
525  * insertions by anyone.
526  *
527  * @param namespace handle to the namespace that should be deleted / freed
528  * @param freeze prevents future insertions; creating a namespace
529  *        with the same name again will create a fresh namespace instead
530  *
531  * @return GNUNET_OK on success, GNUNET_SYSERR on error
532  */
533 int
534 GNUNET_FS_namespace_delete (struct GNUNET_FS_Namespace *namespace, int freeze)
535 {
536   unsigned int i;
537   struct NamespaceUpdateNode *nsn;
538
539   namespace->rc--;
540   if (freeze)
541   {
542     if (0 != UNLINK (namespace->filename))
543       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "unlink",
544                                 namespace->filename);
545   }
546   if (0 == namespace->rc)
547   {
548     GNUNET_CRYPTO_rsa_key_free (namespace->key);
549     GNUNET_free (namespace->filename);
550     GNUNET_free (namespace->name);
551     for (i = 0; i < namespace->update_node_count; i++)
552     {
553       nsn = namespace->update_nodes[i];
554       GNUNET_CONTAINER_meta_data_destroy (nsn->md);
555       GNUNET_FS_uri_destroy (nsn->uri);
556       GNUNET_free (nsn->id);
557       GNUNET_free (nsn->update);
558       GNUNET_free (nsn);
559     }
560     GNUNET_array_grow (namespace->update_nodes, namespace->update_node_count,
561                        0);
562     if (namespace->update_map != NULL)
563       GNUNET_CONTAINER_multihashmap_destroy (namespace->update_map);
564     GNUNET_free (namespace);
565   }
566   return GNUNET_OK;
567 }
568
569
570 /**
571  * Context for the 'process_namespace' callback.
572  * Specifies a function to call on each namespace.
573  */
574 struct ProcessNamespaceContext
575 {
576   /**
577    * Function to call.
578    */
579   GNUNET_FS_NamespaceInfoProcessor cb;
580
581   /**
582    * Closure for 'cb'.
583    */
584   void *cb_cls;
585 };
586
587
588 /**
589  * Function called with a filename of a namespace. Reads the key and
590  * calls the callback.
591  *
592  * @param cls closure (struct ProcessNamespaceContext)
593  * @param filename complete filename (absolute path)
594  * @return GNUNET_OK to continue to iterate,
595  *  GNUNET_SYSERR to abort iteration with error!
596  */
597 static int
598 process_namespace (void *cls, const char *filename)
599 {
600   struct ProcessNamespaceContext *pnc = cls;
601   struct GNUNET_CRYPTO_RsaPrivateKey *key;
602   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
603   GNUNET_HashCode id;
604   const char *name;
605   const char *t;
606
607   key = GNUNET_CRYPTO_rsa_key_create_from_file (filename);
608   if (key == NULL)
609   {
610     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
611                 _
612                 ("Failed to read namespace private key file `%s', deleting it!\n"),
613                 filename);
614     if (0 != UNLINK (filename))
615       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", filename);
616     return GNUNET_OK;
617   }
618   GNUNET_CRYPTO_rsa_key_get_public (key, &pk);
619   GNUNET_CRYPTO_rsa_key_free (key);
620   GNUNET_CRYPTO_hash (&pk, sizeof (pk), &id);
621   name = filename;
622   while (NULL != (t = strstr (name, DIR_SEPARATOR_STR)))
623     name = t + 1;
624   pnc->cb (pnc->cb_cls, name, &id);
625   return GNUNET_OK;
626 }
627
628
629 /**
630  * Build a list of all available local (!) namespaces The returned
631  * names are only the nicknames since we only iterate over the local
632  * namespaces.
633  *
634  * @param h handle to the file sharing subsystem
635  * @param cb function to call on each known namespace
636  * @param cb_cls closure for cb
637  */
638 void
639 GNUNET_FS_namespace_list (struct GNUNET_FS_Handle *h,
640                           GNUNET_FS_NamespaceInfoProcessor cb, void *cb_cls)
641 {
642   char *dn;
643   struct ProcessNamespaceContext ctx;
644
645   dn = get_namespace_directory (h);
646   if (dn == NULL)
647     return;
648   ctx.cb = cb;
649   ctx.cb_cls = cb_cls;
650   GNUNET_DISK_directory_scan (dn, &process_namespace, &ctx);
651   GNUNET_free (dn);
652 }
653
654
655
656
657 /**
658  * Context for the SKS publication.
659  */
660 struct PublishSksContext
661 {
662
663   /**
664    * URI of the new entry in the namespace.
665    */
666   struct GNUNET_FS_Uri *uri;
667
668   /**
669    * Namespace update node to add to namespace on success (or to be
670    * deleted if publishing failed).
671    */
672   struct NamespaceUpdateNode *nsn;
673
674   /**
675    * Namespace we're publishing to.
676    */
677   struct GNUNET_FS_Namespace *namespace;
678
679   /**
680    * Handle to the datastore.
681    */
682   struct GNUNET_DATASTORE_Handle *dsh;
683
684   /**
685    * Function to call once we're done.
686    */
687   GNUNET_FS_PublishContinuation cont;
688
689   /**
690    * Closure for cont.
691    */
692   void *cont_cls;
693
694 };
695
696
697 /**
698  * Function called by the datastore API with
699  * the result from the PUT (SBlock) request.
700  *
701  * @param cls closure of type "struct PublishSksContext*"
702  * @param success GNUNET_OK on success
703  * @param min_expiration minimum expiration time required for content to be stored
704  * @param msg error message (or NULL)
705  */
706 static void
707 sb_put_cont (void *cls, int success, 
708              struct GNUNET_TIME_Absolute min_expiration,
709              const char *msg)
710 {
711   struct PublishSksContext *psc = cls;
712   GNUNET_HashCode hc;
713
714   if (NULL != psc->dsh)
715   {
716     GNUNET_DATASTORE_disconnect (psc->dsh, GNUNET_NO);
717     psc->dsh = NULL;
718   }
719   if (GNUNET_OK != success)
720   {
721     if (psc->cont != NULL)
722       psc->cont (psc->cont_cls, NULL, msg);
723   }
724   else
725   {
726     if (psc->nsn != NULL)
727     {
728       /* FIXME: this can be done much more
729        * efficiently by simply appending to the
730        * file and overwriting the 4-byte header */
731       if (psc->namespace->update_nodes == NULL)
732         read_update_information_graph (psc->namespace);
733       GNUNET_array_append (psc->namespace->update_nodes,
734                            psc->namespace->update_node_count, psc->nsn);
735       if (psc->namespace->update_map != NULL)
736       {
737         GNUNET_CRYPTO_hash (psc->nsn->id, strlen (psc->nsn->id), &hc);
738         GNUNET_CONTAINER_multihashmap_put (psc->namespace->update_map, &hc,
739                                            psc->nsn,
740                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
741       }
742       psc->nsn = NULL;
743       write_update_information_graph (psc->namespace);
744     }
745     if (psc->cont != NULL)
746       psc->cont (psc->cont_cls, psc->uri, NULL);
747   }
748   GNUNET_FS_namespace_delete (psc->namespace, GNUNET_NO);
749   GNUNET_FS_uri_destroy (psc->uri);
750   if (psc->nsn != NULL)
751   {
752     GNUNET_CONTAINER_meta_data_destroy (psc->nsn->md);
753     GNUNET_FS_uri_destroy (psc->nsn->uri);
754     GNUNET_free (psc->nsn->id);
755     GNUNET_free (psc->nsn->update);
756     GNUNET_free (psc->nsn);
757   }
758   GNUNET_free (psc);
759 }
760
761
762 /**
763  * Publish an SBlock on GNUnet.
764  *
765  * @param h handle to the file sharing subsystem
766  * @param namespace namespace to publish in
767  * @param identifier identifier to use
768  * @param update update identifier to use
769  * @param meta metadata to use
770  * @param uri URI to refer to in the SBlock
771  * @param bo block options
772  * @param options publication options
773  * @param cont continuation
774  * @param cont_cls closure for cont
775  */
776 void
777 GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h,
778                        struct GNUNET_FS_Namespace *namespace,
779                        const char *identifier, const char *update,
780                        const struct GNUNET_CONTAINER_MetaData *meta,
781                        const struct GNUNET_FS_Uri *uri,
782                        const struct GNUNET_FS_BlockOptions *bo,
783                        enum GNUNET_FS_PublishOptions options,
784                        GNUNET_FS_PublishContinuation cont, void *cont_cls)
785 {
786   struct PublishSksContext *psc;
787   struct GNUNET_CRYPTO_AesSessionKey sk;
788   struct GNUNET_CRYPTO_AesInitializationVector iv;
789   struct GNUNET_FS_Uri *sks_uri;
790   char *uris;
791   size_t size;
792   size_t slen;
793   size_t nidlen;
794   size_t idlen;
795   ssize_t mdsize;
796   struct SBlock *sb;
797   struct SBlock *sb_enc;
798   char *dest;
799   struct GNUNET_CONTAINER_MetaData *mmeta;
800   GNUNET_HashCode key;          /* hash of thisId = key */
801   GNUNET_HashCode id;           /* hash of hc = identifier */
802   GNUNET_HashCode query;        /* id ^ nsid = DB query */
803
804   if (NULL == meta)
805     mmeta = GNUNET_CONTAINER_meta_data_create ();
806   else
807     mmeta = GNUNET_CONTAINER_meta_data_duplicate (meta);
808   uris = GNUNET_FS_uri_to_string (uri);
809   slen = strlen (uris) + 1;
810   idlen = strlen (identifier);
811   if (update != NULL)
812     nidlen = strlen (update) + 1;
813   else
814     nidlen = 1;
815   mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (mmeta);
816   size = sizeof (struct SBlock) + slen + nidlen + mdsize;
817   if (size > MAX_SBLOCK_SIZE)
818   {
819     size = MAX_SBLOCK_SIZE;
820     mdsize = size - (sizeof (struct SBlock) + slen + nidlen);
821   }
822   sb = GNUNET_malloc (sizeof (struct SBlock) + size);
823   dest = (char *) &sb[1];
824   if (update != NULL)
825     memcpy (dest, update, nidlen);
826   else
827     memset (dest, 0, 1);
828   dest += nidlen;
829   memcpy (dest, uris, slen);
830   GNUNET_free (uris);
831   dest += slen;
832   mdsize =
833       GNUNET_CONTAINER_meta_data_serialize (mmeta, &dest, mdsize,
834                                             GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
835   GNUNET_CONTAINER_meta_data_destroy (mmeta);
836   if (mdsize == -1)
837   {
838     GNUNET_break (0);
839     GNUNET_free (sb);
840     cont (cont_cls, NULL, _("Internal error."));
841     return;
842   }
843   size = sizeof (struct SBlock) + mdsize + slen + nidlen;
844   sb_enc = GNUNET_malloc (size);
845   GNUNET_CRYPTO_hash (identifier, idlen, &key);
846   GNUNET_CRYPTO_hash (&key, sizeof (GNUNET_HashCode), &id);
847   sks_uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri));
848   sks_uri->type = sks;
849   GNUNET_CRYPTO_rsa_key_get_public (namespace->key, &sb_enc->subspace);
850   GNUNET_CRYPTO_hash (&sb_enc->subspace,
851                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
852                       &sks_uri->data.sks.namespace);
853   sks_uri->data.sks.identifier = GNUNET_strdup (identifier);
854   GNUNET_CRYPTO_hash_xor (&id, &sks_uri->data.sks.namespace,
855                           &sb_enc->identifier);
856   GNUNET_CRYPTO_hash_to_aes_key (&key, &sk, &iv);
857   GNUNET_CRYPTO_aes_encrypt (&sb[1], size - sizeof (struct SBlock), &sk, &iv,
858                              &sb_enc[1]);
859   sb_enc->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_SBLOCK);
860   sb_enc->purpose.size =
861       htonl (slen + mdsize + nidlen + sizeof (struct SBlock) -
862              sizeof (struct GNUNET_CRYPTO_RsaSignature));
863   GNUNET_assert (GNUNET_OK ==
864                  GNUNET_CRYPTO_rsa_sign (namespace->key, &sb_enc->purpose,
865                                          &sb_enc->signature));
866   psc = GNUNET_malloc (sizeof (struct PublishSksContext));
867   psc->uri = sks_uri;
868   psc->cont = cont;
869   psc->namespace = namespace;
870   namespace->rc++;
871   psc->cont_cls = cont_cls;
872   if (0 != (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
873   {
874     GNUNET_free (sb_enc);
875     GNUNET_free (sb);
876     sb_put_cont (psc, GNUNET_OK, GNUNET_TIME_UNIT_ZERO_ABS, NULL);
877     return;
878   }
879   psc->dsh = GNUNET_DATASTORE_connect (h->cfg);
880   if (NULL == psc->dsh)
881   {
882     GNUNET_free (sb_enc);
883     GNUNET_free (sb);
884     sb_put_cont (psc, GNUNET_NO, GNUNET_TIME_UNIT_ZERO_ABS, _("Failed to connect to datastore."));
885     return;
886   }
887   GNUNET_CRYPTO_hash_xor (&sks_uri->data.sks.namespace, &id, &query);
888   if (NULL != update)
889   {
890     psc->nsn = GNUNET_malloc (sizeof (struct NamespaceUpdateNode));
891     psc->nsn->id = GNUNET_strdup (identifier);
892     psc->nsn->update = GNUNET_strdup (update);
893     psc->nsn->md = GNUNET_CONTAINER_meta_data_duplicate (meta);
894     psc->nsn->uri = GNUNET_FS_uri_dup (uri);
895   }
896   GNUNET_DATASTORE_put (psc->dsh, 0, &sb_enc->identifier, size, sb_enc,
897                         GNUNET_BLOCK_TYPE_FS_SBLOCK, bo->content_priority,
898                         bo->anonymity_level, bo->replication_level,
899                         bo->expiration_time, -2, 1,
900                         GNUNET_CONSTANTS_SERVICE_TIMEOUT, &sb_put_cont, psc);
901   GNUNET_free (sb);
902   GNUNET_free (sb_enc);
903 }
904
905
906 /**
907  * Closure for 'process_update_node'.
908  */
909 struct ProcessUpdateClosure
910 {
911   /**
912    * Function to call for each node.
913    */
914   GNUNET_FS_IdentifierProcessor ip;
915
916   /**
917    * Closure for 'ip'.
918    */
919   void *ip_cls;
920 };
921
922
923 /**
924  * Call the iterator in the closure for each node.
925  *
926  * @param cls closure (of type 'struct ProcessUpdateClosure *')
927  * @param key current key code
928  * @param value value in the hash map (of type 'struct NamespaceUpdateNode *')
929  * @return GNUNET_YES if we should continue to
930  *         iterate,
931  *         GNUNET_NO if not.
932  */
933 static int
934 process_update_node (void *cls, const GNUNET_HashCode * key, void *value)
935 {
936   struct ProcessUpdateClosure *pc = cls;
937   struct NamespaceUpdateNode *nsn = value;
938
939   pc->ip (pc->ip_cls, nsn->id, nsn->uri, nsn->md, nsn->update);
940   return GNUNET_YES;
941 }
942
943
944 /**
945  * Closure for 'find_trees'.
946  */
947 struct FindTreeClosure
948 {
949   /**
950    * Namespace we are operating on.
951    */
952   struct GNUNET_FS_Namespace *namespace;
953
954   /**
955    * Array with 'head's of TREEs.
956    */
957   struct NamespaceUpdateNode **tree_array;
958
959   /**
960    * Size of 'tree_array'
961    */
962   unsigned int tree_array_size;
963
964   /**
965    * Current generational ID used.
966    */
967   unsigned int nug;
968
969   /**
970    * Identifier for the current TREE, or UINT_MAX for none yet.
971    */
972   unsigned int id;
973 };
974
975
976 /**
977  * Find all nodes reachable from the current node (including the
978  * current node itself).  If they are in no tree, add them to the
979  * current one.   If they are the head of another tree, merge the
980  * trees.  If they are in the middle of another tree, let them be.
981  * We can tell that a node is already in an tree by checking if
982  * its 'nug' field is set to the current 'nug' value.  It is the
983  * head of an tree if it is in the 'tree_array' under its respective
984  * 'tree_id'.
985  *
986  * In short, we're trying to find the smallest number of tree to
987  * cover a directed graph.
988  *
989  * @param cls closure (of type 'struct FindTreeClosure')
990  * @param key current key code
991  * @param value value in the hash map
992  * @return GNUNET_YES if we should continue to
993  *         iterate,
994  *         GNUNET_NO if not.
995  */
996 static int
997 find_trees (void *cls, const GNUNET_HashCode * key, void *value)
998 {
999   struct FindTreeClosure *fc = cls;
1000   struct NamespaceUpdateNode *nsn = value;
1001   GNUNET_HashCode hc;
1002
1003   if (nsn->nug == fc->nug)
1004   {
1005     if (nsn->tree_id == UINT_MAX)
1006       return GNUNET_YES;        /* circular */
1007     GNUNET_assert (nsn->tree_id < fc->tree_array_size);
1008     if (fc->tree_array[nsn->tree_id] != nsn)
1009       return GNUNET_YES;        /* part of "another" (directed) TREE,
1010                                  * and not root of it, end trace */
1011     if (nsn->tree_id == fc->id)
1012       return GNUNET_YES;        /* that's our own root (can this be?) */
1013     /* merge existing TREE, we have a root for both */
1014     fc->tree_array[nsn->tree_id] = NULL;
1015     if (fc->id == UINT_MAX)
1016       fc->id = nsn->tree_id;    /* take over ID */
1017   }
1018   else
1019   {
1020     nsn->nug = fc->nug;
1021     nsn->tree_id = UINT_MAX;    /* mark as undef */
1022     /* trace */
1023     GNUNET_CRYPTO_hash (nsn->update, strlen (nsn->update), &hc);
1024     GNUNET_CONTAINER_multihashmap_get_multiple (fc->namespace->update_map, &hc,
1025                                                 &find_trees, fc);
1026   }
1027   return GNUNET_YES;
1028 }
1029
1030
1031 /**
1032  * List all of the identifiers in the namespace for which we could
1033  * produce an update.  Namespace updates form a graph where each node
1034  * has a name.  Each node can have any number of URI/meta-data entries
1035  * which can each be linked to other nodes.  Cycles are possible.
1036  *
1037  * Calling this function with "next_id" NULL will cause the library to
1038  * call "ip" with a root for each strongly connected component of the
1039  * graph (a root being a node from which all other nodes in the Tree
1040  * are reachable).
1041  *
1042  * Calling this function with "next_id" being the name of a node will
1043  * cause the library to call "ip" with all children of the node.  Note
1044  * that cycles within the final tree are possible (including self-loops).
1045  * I know, odd definition of a tree, but the GUI will display an actual
1046  * tree (GtkTreeView), so that's what counts for the term here.
1047  *
1048  * @param namespace namespace to inspect for updateable content
1049  * @param next_id ID to look for; use NULL to look for tree roots
1050  * @param ip function to call on each updateable identifier
1051  * @param ip_cls closure for ip
1052  */
1053 void
1054 GNUNET_FS_namespace_list_updateable (struct GNUNET_FS_Namespace *namespace,
1055                                      const char *next_id,
1056                                      GNUNET_FS_IdentifierProcessor ip,
1057                                      void *ip_cls)
1058 {
1059   unsigned int i;
1060   unsigned int nug;
1061   GNUNET_HashCode hc;
1062   struct NamespaceUpdateNode *nsn;
1063   struct ProcessUpdateClosure pc;
1064   struct FindTreeClosure fc;
1065
1066   if (namespace->update_nodes == NULL)
1067     read_update_information_graph (namespace);
1068   if (namespace->update_nodes == NULL)
1069   {
1070 #if DEBUG_NAMESPACE
1071     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1072                 "No updateable nodes found for ID `%s'\n", next_id);
1073 #endif
1074     return;                     /* no nodes */
1075   }
1076   if (namespace->update_map == NULL)
1077   {
1078     /* need to construct */
1079     namespace->update_map =
1080         GNUNET_CONTAINER_multihashmap_create (2 +
1081                                               3 * namespace->update_node_count /
1082                                               4);
1083     for (i = 0; i < namespace->update_node_count; i++)
1084     {
1085       nsn = namespace->update_nodes[i];
1086       GNUNET_CRYPTO_hash (nsn->id, strlen (nsn->id), &hc);
1087       GNUNET_CONTAINER_multihashmap_put (namespace->update_map, &hc, nsn,
1088                                          GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1089     }
1090   }
1091   if (next_id != NULL)
1092   {
1093     GNUNET_CRYPTO_hash (next_id, strlen (next_id), &hc);
1094     pc.ip = ip;
1095     pc.ip_cls = ip_cls;
1096     GNUNET_CONTAINER_multihashmap_get_multiple (namespace->update_map, &hc,
1097                                                 &process_update_node, &pc);
1098     return;
1099   }
1100 #if DEBUG_NAMESPACE
1101   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1102               "Calculating TREEs to find roots of update trees\n");
1103 #endif
1104   /* Find heads of TREEs in update graph */
1105   nug = ++namespace->nug_gen;
1106   fc.tree_array = NULL;
1107   fc.tree_array_size = 0;
1108
1109   for (i = 0; i < namespace->update_node_count; i++)
1110   {
1111     nsn = namespace->update_nodes[i];
1112     if (nsn->nug == nug)
1113     {
1114 #if DEBUG_NAMESPACE
1115       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TREE of node `%s' is %u\n", nsn->id,
1116                   nsn->nug);
1117 #endif
1118       continue;                 /* already placed in TREE */
1119     }
1120     GNUNET_CRYPTO_hash (nsn->update, strlen (nsn->update), &hc);
1121     nsn->nug = nug;
1122     nsn->tree_id = UINT_MAX;
1123     fc.id = UINT_MAX;
1124     fc.nug = nug;
1125     fc.namespace = namespace;
1126     GNUNET_CONTAINER_multihashmap_get_multiple (namespace->update_map, &hc,
1127                                                 &find_trees, &fc);
1128     if (fc.id == UINT_MAX)
1129     {
1130       /* start new TREE */
1131       for (fc.id = 0; fc.id < fc.tree_array_size; fc.id++)
1132       {
1133         if (fc.tree_array[fc.id] == NULL)
1134         {
1135           fc.tree_array[fc.id] = nsn;
1136           nsn->tree_id = fc.id;
1137           break;
1138         }
1139       }
1140       if (fc.id == fc.tree_array_size)
1141       {
1142         GNUNET_array_append (fc.tree_array, fc.tree_array_size, nsn);
1143         nsn->tree_id = fc.id;
1144       }
1145 #if DEBUG_NAMESPACE
1146       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1147                   "Starting new TREE %u with node `%s'\n", nsn->tree_id,
1148                   nsn->id);
1149 #endif
1150       /* put all nodes with same identifier into this TREE */
1151       GNUNET_CRYPTO_hash (nsn->id, strlen (nsn->id), &hc);
1152       fc.id = nsn->tree_id;
1153       fc.nug = nug;
1154       fc.namespace = namespace;
1155       GNUNET_CONTAINER_multihashmap_get_multiple (namespace->update_map, &hc,
1156                                                   &find_trees, &fc);
1157     }
1158     else
1159     {
1160       /* make head of TREE "id" */
1161       fc.tree_array[fc.id] = nsn;
1162       nsn->tree_id = fc.id;
1163     }
1164 #if DEBUG_NAMESPACE
1165     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TREE of node `%s' is %u\n", nsn->id,
1166                 fc.id);
1167 #endif
1168   }
1169   for (i = 0; i < fc.tree_array_size; i++)
1170   {
1171     nsn = fc.tree_array[i];
1172     if (NULL != nsn)
1173     {
1174 #if DEBUG_NAMESPACE
1175       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Root of TREE %u is node `%s'\n", i,
1176                   nsn->id);
1177 #endif
1178
1179       ip (ip_cls, nsn->id, nsn->uri, nsn->md, nsn->update);
1180     }
1181   }
1182   GNUNET_array_grow (fc.tree_array, fc.tree_array_size, 0);
1183 #if DEBUG_NAMESPACE
1184   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Done processing TREEs\n");
1185 #endif
1186 }
1187
1188
1189 /* end of fs_namespace.c */