added ATS addresstype information to unix
[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 msg NULL on success, otherwise an error message
315  */
316 static void
317 advertisement_cont (void *cls, int success, const char *msg)
318 {
319   struct AdvertisementContext *ac = cls;
320   const char *keyword;
321   GNUNET_HashCode key;
322   GNUNET_HashCode query;
323   struct GNUNET_CRYPTO_AesSessionKey skey;
324   struct GNUNET_CRYPTO_AesInitializationVector iv;
325   struct GNUNET_CRYPTO_RsaPrivateKey *pk;
326
327   if (GNUNET_OK != success)
328   {
329     /* error! */
330     GNUNET_SCHEDULER_add_continuation (&do_disconnect, ac->dsh,
331                                        GNUNET_SCHEDULER_REASON_PREREQ_DONE);
332     if (msg == NULL)
333     {
334       GNUNET_break (0);
335       msg = _("Unknown error");
336     }
337     if (ac->cont != NULL)
338       ac->cont (ac->cont_cls, NULL, msg);
339     GNUNET_FS_uri_destroy (ac->ksk_uri);
340     GNUNET_free (ac->pt);
341     GNUNET_free (ac->nb);
342     GNUNET_FS_namespace_delete (ac->ns, GNUNET_NO);
343     GNUNET_free (ac);
344     return;
345   }
346   if (ac->pos == ac->ksk_uri->data.ksk.keywordCount)
347   {
348     /* done! */
349     GNUNET_SCHEDULER_add_continuation (&do_disconnect, ac->dsh,
350                                        GNUNET_SCHEDULER_REASON_PREREQ_DONE);
351     if (ac->cont != NULL)
352       ac->cont (ac->cont_cls, ac->ksk_uri, NULL);
353     GNUNET_FS_uri_destroy (ac->ksk_uri);
354     GNUNET_free (ac->pt);
355     GNUNET_free (ac->nb);
356     GNUNET_FS_namespace_delete (ac->ns, GNUNET_NO);
357     GNUNET_free (ac);
358     return;
359   }
360   keyword = ac->ksk_uri->data.ksk.keywords[ac->pos++];
361   /* first character of keyword indicates if it is
362    * mandatory or not -- ignore for hashing */
363   GNUNET_CRYPTO_hash (&keyword[1], strlen (&keyword[1]), &key);
364   GNUNET_CRYPTO_hash_to_aes_key (&key, &skey, &iv);
365   GNUNET_CRYPTO_aes_encrypt (ac->pt, ac->pt_size, &skey, &iv, &ac->nb[1]);
366   GNUNET_break (GNUNET_OK ==
367                 GNUNET_CRYPTO_rsa_sign (ac->ns->key, &ac->nb->ns_purpose,
368                                         &ac->nb->ns_signature));
369   pk = GNUNET_CRYPTO_rsa_key_create_from_hash (&key);
370   GNUNET_assert (pk != NULL);
371   GNUNET_CRYPTO_rsa_key_get_public (pk, &ac->nb->keyspace);
372   GNUNET_CRYPTO_hash (&ac->nb->keyspace,
373                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
374                       &query);
375   GNUNET_break (GNUNET_OK ==
376                 GNUNET_CRYPTO_rsa_sign (pk, &ac->nb->ksk_purpose,
377                                         &ac->nb->ksk_signature));
378   GNUNET_CRYPTO_rsa_key_free (pk);
379   GNUNET_DATASTORE_put (ac->dsh, 0 /* no reservation */ ,
380                         &query, ac->pt_size + sizeof (struct NBlock), ac->nb,
381                         GNUNET_BLOCK_TYPE_FS_NBLOCK, ac->bo.content_priority,
382                         ac->bo.anonymity_level, ac->bo.replication_level,
383                         ac->bo.expiration_time, -2, 1,
384                         GNUNET_CONSTANTS_SERVICE_TIMEOUT, &advertisement_cont,
385                         ac);
386 }
387
388
389 /**
390  * Publish an advertismement for a namespace.
391  *
392  * @param h handle to the file sharing subsystem
393  * @param ksk_uri keywords to use for advertisment
394  * @param namespace handle for the namespace that should be advertised
395  * @param meta meta-data for the namespace advertisement
396  * @param bo block options
397  * @param rootEntry name of the root of the namespace
398  * @param cont continuation
399  * @param cont_cls closure for cont
400  */
401 void
402 GNUNET_FS_namespace_advertise (struct GNUNET_FS_Handle *h,
403                                struct GNUNET_FS_Uri *ksk_uri,
404                                struct GNUNET_FS_Namespace *namespace,
405                                const struct GNUNET_CONTAINER_MetaData *meta,
406                                const struct GNUNET_FS_BlockOptions *bo,
407                                const char *rootEntry,
408                                GNUNET_FS_PublishContinuation cont,
409                                void *cont_cls)
410 {
411   size_t reslen;
412   size_t size;
413   ssize_t mdsize;
414   struct NBlock *nb;
415   char *mdst;
416   struct GNUNET_DATASTORE_Handle *dsh;
417   struct AdvertisementContext *ctx;
418   char *pt;
419
420   /* create advertisements */
421   mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta);
422   if (-1 == mdsize)
423   {
424     cont (cont_cls, NULL, _("Failed to serialize meta data"));
425     return;
426   }
427   reslen = strlen (rootEntry) + 1;
428   size = mdsize + sizeof (struct NBlock) + reslen;
429   if (size > MAX_NBLOCK_SIZE)
430   {
431     size = MAX_NBLOCK_SIZE;
432     mdsize = size - sizeof (struct NBlock) - reslen;
433   }
434
435   pt = GNUNET_malloc (mdsize + reslen);
436   memcpy (pt, rootEntry, reslen);
437   mdst = &pt[reslen];
438   mdsize =
439       GNUNET_CONTAINER_meta_data_serialize (meta, &mdst, mdsize,
440                                             GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
441   if (mdsize == -1)
442   {
443     GNUNET_break (0);
444     GNUNET_free (pt);
445     cont (cont_cls, NULL, _("Failed to serialize meta data"));
446     return;
447   }
448   size = mdsize + sizeof (struct NBlock) + reslen;
449   nb = GNUNET_malloc (size);
450   GNUNET_CRYPTO_rsa_key_get_public (namespace->key, &nb->subspace);
451   nb->ns_purpose.size =
452       htonl (mdsize + reslen +
453              sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
454              sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
455   nb->ns_purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK);
456   nb->ksk_purpose.size =
457       htonl (size - sizeof (struct GNUNET_CRYPTO_RsaSignature));
458   nb->ksk_purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK_KSIG);
459   dsh = GNUNET_DATASTORE_connect (h->cfg);
460   if (NULL == dsh)
461   {
462     GNUNET_free (nb);
463     GNUNET_free (pt);
464     cont (cont_cls, NULL, _("Failed to connect to datastore service"));
465     return;
466   }
467   ctx = GNUNET_malloc (sizeof (struct AdvertisementContext));
468   ctx->cont = cont;
469   ctx->cont_cls = cont_cls;
470   ctx->dsh = dsh;
471   ctx->ksk_uri = GNUNET_FS_uri_dup (ksk_uri);
472   ctx->nb = nb;
473   ctx->pt = pt;
474   ctx->pt_size = mdsize + reslen;
475   ctx->ns = namespace;
476   ctx->ns->rc++;
477   ctx->bo = *bo;
478   advertisement_cont (ctx, GNUNET_OK, NULL);
479 }
480
481
482 /**
483  * Create a namespace with the given name; if one already
484  * exists, return a handle to the existing namespace.
485  *
486  * @param h handle to the file sharing subsystem
487  * @param name name to use for the namespace
488  * @return handle to the namespace, NULL on error
489  */
490 struct GNUNET_FS_Namespace *
491 GNUNET_FS_namespace_create (struct GNUNET_FS_Handle *h, const char *name)
492 {
493   char *dn;
494   char *fn;
495   struct GNUNET_FS_Namespace *ret;
496
497   dn = get_namespace_directory (h);
498   GNUNET_asprintf (&fn, "%s%s%s", dn, DIR_SEPARATOR_STR, name);
499   GNUNET_free (dn);
500   ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Namespace));
501   ret->h = h;
502   ret->rc = 1;
503   ret->key = GNUNET_CRYPTO_rsa_key_create_from_file (fn);
504   if (ret->key == NULL)
505   {
506     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
507                 _("Failed to create or read private key for namespace `%s'\n"),
508                 name);
509     GNUNET_free (ret);
510     GNUNET_free (fn);
511     return NULL;
512   }
513   ret->name = GNUNET_strdup (name);
514   ret->filename = fn;
515   return ret;
516 }
517
518
519 /**
520  * Delete a namespace handle.  Can be used for a clean shutdown (free
521  * memory) or also to freeze the namespace to prevent further
522  * insertions by anyone.
523  *
524  * @param namespace handle to the namespace that should be deleted / freed
525  * @param freeze prevents future insertions; creating a namespace
526  *        with the same name again will create a fresh namespace instead
527  *
528  * @return GNUNET_OK on success, GNUNET_SYSERR on error
529  */
530 int
531 GNUNET_FS_namespace_delete (struct GNUNET_FS_Namespace *namespace, int freeze)
532 {
533   unsigned int i;
534   struct NamespaceUpdateNode *nsn;
535
536   namespace->rc--;
537   if (freeze)
538   {
539     if (0 != UNLINK (namespace->filename))
540       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "unlink",
541                                 namespace->filename);
542   }
543   if (0 == namespace->rc)
544   {
545     GNUNET_CRYPTO_rsa_key_free (namespace->key);
546     GNUNET_free (namespace->filename);
547     GNUNET_free (namespace->name);
548     for (i = 0; i < namespace->update_node_count; i++)
549     {
550       nsn = namespace->update_nodes[i];
551       GNUNET_CONTAINER_meta_data_destroy (nsn->md);
552       GNUNET_FS_uri_destroy (nsn->uri);
553       GNUNET_free (nsn->id);
554       GNUNET_free (nsn->update);
555       GNUNET_free (nsn);
556     }
557     GNUNET_array_grow (namespace->update_nodes, namespace->update_node_count,
558                        0);
559     if (namespace->update_map != NULL)
560       GNUNET_CONTAINER_multihashmap_destroy (namespace->update_map);
561     GNUNET_free (namespace);
562   }
563   return GNUNET_OK;
564 }
565
566
567 /**
568  * Context for the 'process_namespace' callback.
569  * Specifies a function to call on each namespace.
570  */
571 struct ProcessNamespaceContext
572 {
573   /**
574    * Function to call.
575    */
576   GNUNET_FS_NamespaceInfoProcessor cb;
577
578   /**
579    * Closure for 'cb'.
580    */
581   void *cb_cls;
582 };
583
584
585 /**
586  * Function called with a filename of a namespace. Reads the key and
587  * calls the callback.
588  *
589  * @param cls closure (struct ProcessNamespaceContext)
590  * @param filename complete filename (absolute path)
591  * @return GNUNET_OK to continue to iterate,
592  *  GNUNET_SYSERR to abort iteration with error!
593  */
594 static int
595 process_namespace (void *cls, const char *filename)
596 {
597   struct ProcessNamespaceContext *pnc = cls;
598   struct GNUNET_CRYPTO_RsaPrivateKey *key;
599   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
600   GNUNET_HashCode id;
601   const char *name;
602   const char *t;
603
604   key = GNUNET_CRYPTO_rsa_key_create_from_file (filename);
605   if (key == NULL)
606   {
607     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
608                 _
609                 ("Failed to read namespace private key file `%s', deleting it!\n"),
610                 filename);
611     if (0 != UNLINK (filename))
612       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", filename);
613     return GNUNET_OK;
614   }
615   GNUNET_CRYPTO_rsa_key_get_public (key, &pk);
616   GNUNET_CRYPTO_rsa_key_free (key);
617   GNUNET_CRYPTO_hash (&pk, sizeof (pk), &id);
618   name = filename;
619   while (NULL != (t = strstr (name, DIR_SEPARATOR_STR)))
620     name = t + 1;
621   pnc->cb (pnc->cb_cls, name, &id);
622   return GNUNET_OK;
623 }
624
625
626 /**
627  * Build a list of all available local (!) namespaces The returned
628  * names are only the nicknames since we only iterate over the local
629  * namespaces.
630  *
631  * @param h handle to the file sharing subsystem
632  * @param cb function to call on each known namespace
633  * @param cb_cls closure for cb
634  */
635 void
636 GNUNET_FS_namespace_list (struct GNUNET_FS_Handle *h,
637                           GNUNET_FS_NamespaceInfoProcessor cb, void *cb_cls)
638 {
639   char *dn;
640   struct ProcessNamespaceContext ctx;
641
642   dn = get_namespace_directory (h);
643   if (dn == NULL)
644     return;
645   ctx.cb = cb;
646   ctx.cb_cls = cb_cls;
647   GNUNET_DISK_directory_scan (dn, &process_namespace, &ctx);
648   GNUNET_free (dn);
649 }
650
651
652
653
654 /**
655  * Context for the SKS publication.
656  */
657 struct PublishSksContext
658 {
659
660   /**
661    * URI of the new entry in the namespace.
662    */
663   struct GNUNET_FS_Uri *uri;
664
665   /**
666    * Namespace update node to add to namespace on success (or to be
667    * deleted if publishing failed).
668    */
669   struct NamespaceUpdateNode *nsn;
670
671   /**
672    * Namespace we're publishing to.
673    */
674   struct GNUNET_FS_Namespace *namespace;
675
676   /**
677    * Handle to the datastore.
678    */
679   struct GNUNET_DATASTORE_Handle *dsh;
680
681   /**
682    * Function to call once we're done.
683    */
684   GNUNET_FS_PublishContinuation cont;
685
686   /**
687    * Closure for cont.
688    */
689   void *cont_cls;
690
691 };
692
693
694 /**
695  * Function called by the datastore API with
696  * the result from the PUT (SBlock) request.
697  *
698  * @param cls closure of type "struct PublishSksContext*"
699  * @param success GNUNET_OK on success
700  * @param msg error message (or NULL)
701  */
702 static void
703 sb_put_cont (void *cls, int success, const char *msg)
704 {
705   struct PublishSksContext *psc = cls;
706   GNUNET_HashCode hc;
707
708   if (NULL != psc->dsh)
709   {
710     GNUNET_DATASTORE_disconnect (psc->dsh, GNUNET_NO);
711     psc->dsh = NULL;
712   }
713   if (GNUNET_OK != success)
714   {
715     if (psc->cont != NULL)
716       psc->cont (psc->cont_cls, NULL, msg);
717   }
718   else
719   {
720     if (psc->nsn != NULL)
721     {
722       /* FIXME: this can be done much more
723        * efficiently by simply appending to the
724        * file and overwriting the 4-byte header */
725       if (psc->namespace->update_nodes == NULL)
726         read_update_information_graph (psc->namespace);
727       GNUNET_array_append (psc->namespace->update_nodes,
728                            psc->namespace->update_node_count, psc->nsn);
729       if (psc->namespace->update_map != NULL)
730       {
731         GNUNET_CRYPTO_hash (psc->nsn->id, strlen (psc->nsn->id), &hc);
732         GNUNET_CONTAINER_multihashmap_put (psc->namespace->update_map, &hc,
733                                            psc->nsn,
734                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
735       }
736       psc->nsn = NULL;
737       write_update_information_graph (psc->namespace);
738     }
739     if (psc->cont != NULL)
740       psc->cont (psc->cont_cls, psc->uri, NULL);
741   }
742   GNUNET_FS_namespace_delete (psc->namespace, GNUNET_NO);
743   GNUNET_FS_uri_destroy (psc->uri);
744   if (psc->nsn != NULL)
745   {
746     GNUNET_CONTAINER_meta_data_destroy (psc->nsn->md);
747     GNUNET_FS_uri_destroy (psc->nsn->uri);
748     GNUNET_free (psc->nsn->id);
749     GNUNET_free (psc->nsn->update);
750     GNUNET_free (psc->nsn);
751   }
752   GNUNET_free (psc);
753 }
754
755
756 /**
757  * Publish an SBlock on GNUnet.
758  *
759  * @param h handle to the file sharing subsystem
760  * @param namespace namespace to publish in
761  * @param identifier identifier to use
762  * @param update update identifier to use
763  * @param meta metadata to use
764  * @param uri URI to refer to in the SBlock
765  * @param bo block options
766  * @param options publication options
767  * @param cont continuation
768  * @param cont_cls closure for cont
769  */
770 void
771 GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h,
772                        struct GNUNET_FS_Namespace *namespace,
773                        const char *identifier, const char *update,
774                        const struct GNUNET_CONTAINER_MetaData *meta,
775                        const struct GNUNET_FS_Uri *uri,
776                        const struct GNUNET_FS_BlockOptions *bo,
777                        enum GNUNET_FS_PublishOptions options,
778                        GNUNET_FS_PublishContinuation cont, void *cont_cls)
779 {
780   struct PublishSksContext *psc;
781   struct GNUNET_CRYPTO_AesSessionKey sk;
782   struct GNUNET_CRYPTO_AesInitializationVector iv;
783   struct GNUNET_FS_Uri *sks_uri;
784   char *uris;
785   size_t size;
786   size_t slen;
787   size_t nidlen;
788   size_t idlen;
789   ssize_t mdsize;
790   struct SBlock *sb;
791   struct SBlock *sb_enc;
792   char *dest;
793   struct GNUNET_CONTAINER_MetaData *mmeta;
794   GNUNET_HashCode key;          /* hash of thisId = key */
795   GNUNET_HashCode id;           /* hash of hc = identifier */
796   GNUNET_HashCode query;        /* id ^ nsid = DB query */
797
798   if (NULL == meta)
799     mmeta = GNUNET_CONTAINER_meta_data_create ();
800   else
801     mmeta = GNUNET_CONTAINER_meta_data_duplicate (meta);
802   uris = GNUNET_FS_uri_to_string (uri);
803   slen = strlen (uris) + 1;
804   idlen = strlen (identifier);
805   if (update != NULL)
806     nidlen = strlen (update) + 1;
807   else
808     nidlen = 1;
809   mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (mmeta);
810   size = sizeof (struct SBlock) + slen + nidlen + mdsize;
811   if (size > MAX_SBLOCK_SIZE)
812   {
813     size = MAX_SBLOCK_SIZE;
814     mdsize = size - (sizeof (struct SBlock) + slen + nidlen);
815   }
816   sb = GNUNET_malloc (sizeof (struct SBlock) + size);
817   dest = (char *) &sb[1];
818   if (update != NULL)
819     memcpy (dest, update, nidlen);
820   else
821     memset (dest, 0, 1);
822   dest += nidlen;
823   memcpy (dest, uris, slen);
824   GNUNET_free (uris);
825   dest += slen;
826   mdsize =
827       GNUNET_CONTAINER_meta_data_serialize (mmeta, &dest, mdsize,
828                                             GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
829   GNUNET_CONTAINER_meta_data_destroy (mmeta);
830   if (mdsize == -1)
831   {
832     GNUNET_break (0);
833     GNUNET_free (sb);
834     cont (cont_cls, NULL, _("Internal error."));
835     return;
836   }
837   size = sizeof (struct SBlock) + mdsize + slen + nidlen;
838   sb_enc = GNUNET_malloc (size);
839   GNUNET_CRYPTO_hash (identifier, idlen, &key);
840   GNUNET_CRYPTO_hash (&key, sizeof (GNUNET_HashCode), &id);
841   sks_uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri));
842   sks_uri->type = sks;
843   GNUNET_CRYPTO_rsa_key_get_public (namespace->key, &sb_enc->subspace);
844   GNUNET_CRYPTO_hash (&sb_enc->subspace,
845                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
846                       &sks_uri->data.sks.namespace);
847   sks_uri->data.sks.identifier = GNUNET_strdup (identifier);
848   GNUNET_CRYPTO_hash_xor (&id, &sks_uri->data.sks.namespace,
849                           &sb_enc->identifier);
850   GNUNET_CRYPTO_hash_to_aes_key (&key, &sk, &iv);
851   GNUNET_CRYPTO_aes_encrypt (&sb[1], size - sizeof (struct SBlock), &sk, &iv,
852                              &sb_enc[1]);
853   sb_enc->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_SBLOCK);
854   sb_enc->purpose.size =
855       htonl (slen + mdsize + nidlen + sizeof (struct SBlock) -
856              sizeof (struct GNUNET_CRYPTO_RsaSignature));
857   GNUNET_assert (GNUNET_OK ==
858                  GNUNET_CRYPTO_rsa_sign (namespace->key, &sb_enc->purpose,
859                                          &sb_enc->signature));
860   psc = GNUNET_malloc (sizeof (struct PublishSksContext));
861   psc->uri = sks_uri;
862   psc->cont = cont;
863   psc->namespace = namespace;
864   namespace->rc++;
865   psc->cont_cls = cont_cls;
866   if (0 != (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
867   {
868     GNUNET_free (sb_enc);
869     GNUNET_free (sb);
870     sb_put_cont (psc, GNUNET_OK, NULL);
871     return;
872   }
873   psc->dsh = GNUNET_DATASTORE_connect (h->cfg);
874   if (NULL == psc->dsh)
875   {
876     GNUNET_free (sb_enc);
877     GNUNET_free (sb);
878     sb_put_cont (psc, GNUNET_NO, _("Failed to connect to datastore."));
879     return;
880   }
881   GNUNET_CRYPTO_hash_xor (&sks_uri->data.sks.namespace, &id, &query);
882   if (NULL != update)
883   {
884     psc->nsn = GNUNET_malloc (sizeof (struct NamespaceUpdateNode));
885     psc->nsn->id = GNUNET_strdup (identifier);
886     psc->nsn->update = GNUNET_strdup (update);
887     psc->nsn->md = GNUNET_CONTAINER_meta_data_duplicate (meta);
888     psc->nsn->uri = GNUNET_FS_uri_dup (uri);
889   }
890   GNUNET_DATASTORE_put (psc->dsh, 0, &sb_enc->identifier, size, sb_enc,
891                         GNUNET_BLOCK_TYPE_FS_SBLOCK, bo->content_priority,
892                         bo->anonymity_level, bo->replication_level,
893                         bo->expiration_time, -2, 1,
894                         GNUNET_CONSTANTS_SERVICE_TIMEOUT, &sb_put_cont, psc);
895   GNUNET_free (sb);
896   GNUNET_free (sb_enc);
897 }
898
899
900 /**
901  * Closure for 'process_update_node'.
902  */
903 struct ProcessUpdateClosure
904 {
905   /**
906    * Function to call for each node.
907    */
908   GNUNET_FS_IdentifierProcessor ip;
909
910   /**
911    * Closure for 'ip'.
912    */
913   void *ip_cls;
914 };
915
916
917 /**
918  * Call the iterator in the closure for each node.
919  *
920  * @param cls closure (of type 'struct ProcessUpdateClosure *')
921  * @param key current key code
922  * @param value value in the hash map (of type 'struct NamespaceUpdateNode *')
923  * @return GNUNET_YES if we should continue to
924  *         iterate,
925  *         GNUNET_NO if not.
926  */
927 static int
928 process_update_node (void *cls, const GNUNET_HashCode * key, void *value)
929 {
930   struct ProcessUpdateClosure *pc = cls;
931   struct NamespaceUpdateNode *nsn = value;
932
933   pc->ip (pc->ip_cls, nsn->id, nsn->uri, nsn->md, nsn->update);
934   return GNUNET_YES;
935 }
936
937
938 /**
939  * Closure for 'find_trees'.
940  */
941 struct FindTreeClosure
942 {
943   /**
944    * Namespace we are operating on.
945    */
946   struct GNUNET_FS_Namespace *namespace;
947
948   /**
949    * Array with 'head's of TREEs.
950    */
951   struct NamespaceUpdateNode **tree_array;
952
953   /**
954    * Size of 'tree_array'
955    */
956   unsigned int tree_array_size;
957
958   /**
959    * Current generational ID used.
960    */
961   unsigned int nug;
962
963   /**
964    * Identifier for the current TREE, or UINT_MAX for none yet.
965    */
966   unsigned int id;
967 };
968
969
970 /**
971  * Find all nodes reachable from the current node (including the
972  * current node itself).  If they are in no tree, add them to the
973  * current one.   If they are the head of another tree, merge the
974  * trees.  If they are in the middle of another tree, let them be.
975  * We can tell that a node is already in an tree by checking if
976  * its 'nug' field is set to the current 'nug' value.  It is the
977  * head of an tree if it is in the 'tree_array' under its respective
978  * 'tree_id'.
979  *
980  * In short, we're trying to find the smallest number of tree to
981  * cover a directed graph.
982  *
983  * @param cls closure (of type 'struct FindTreeClosure')
984  * @param key current key code
985  * @param value value in the hash map
986  * @return GNUNET_YES if we should continue to
987  *         iterate,
988  *         GNUNET_NO if not.
989  */
990 static int
991 find_trees (void *cls, const GNUNET_HashCode * key, void *value)
992 {
993   struct FindTreeClosure *fc = cls;
994   struct NamespaceUpdateNode *nsn = value;
995   GNUNET_HashCode hc;
996
997   if (nsn->nug == fc->nug)
998   {
999     if (nsn->tree_id == UINT_MAX)
1000       return GNUNET_YES;        /* circular */
1001     GNUNET_assert (nsn->tree_id < fc->tree_array_size);
1002     if (fc->tree_array[nsn->tree_id] != nsn)
1003       return GNUNET_YES;        /* part of "another" (directed) TREE,
1004                                  * and not root of it, end trace */
1005     if (nsn->tree_id == fc->id)
1006       return GNUNET_YES;        /* that's our own root (can this be?) */
1007     /* merge existing TREE, we have a root for both */
1008     fc->tree_array[nsn->tree_id] = NULL;
1009     if (fc->id == UINT_MAX)
1010       fc->id = nsn->tree_id;    /* take over ID */
1011   }
1012   else
1013   {
1014     nsn->nug = fc->nug;
1015     nsn->tree_id = UINT_MAX;    /* mark as undef */
1016     /* trace */
1017     GNUNET_CRYPTO_hash (nsn->update, strlen (nsn->update), &hc);
1018     GNUNET_CONTAINER_multihashmap_get_multiple (fc->namespace->update_map, &hc,
1019                                                 &find_trees, fc);
1020   }
1021   return GNUNET_YES;
1022 }
1023
1024
1025 /**
1026  * List all of the identifiers in the namespace for which we could
1027  * produce an update.  Namespace updates form a graph where each node
1028  * has a name.  Each node can have any number of URI/meta-data entries
1029  * which can each be linked to other nodes.  Cycles are possible.
1030  *
1031  * Calling this function with "next_id" NULL will cause the library to
1032  * call "ip" with a root for each strongly connected component of the
1033  * graph (a root being a node from which all other nodes in the Tree
1034  * are reachable).
1035  *
1036  * Calling this function with "next_id" being the name of a node will
1037  * cause the library to call "ip" with all children of the node.  Note
1038  * that cycles within the final tree are possible (including self-loops).
1039  * I know, odd definition of a tree, but the GUI will display an actual
1040  * tree (GtkTreeView), so that's what counts for the term here.
1041  *
1042  * @param namespace namespace to inspect for updateable content
1043  * @param next_id ID to look for; use NULL to look for tree roots
1044  * @param ip function to call on each updateable identifier
1045  * @param ip_cls closure for ip
1046  */
1047 void
1048 GNUNET_FS_namespace_list_updateable (struct GNUNET_FS_Namespace *namespace,
1049                                      const char *next_id,
1050                                      GNUNET_FS_IdentifierProcessor ip,
1051                                      void *ip_cls)
1052 {
1053   unsigned int i;
1054   unsigned int nug;
1055   GNUNET_HashCode hc;
1056   struct NamespaceUpdateNode *nsn;
1057   struct ProcessUpdateClosure pc;
1058   struct FindTreeClosure fc;
1059
1060   if (namespace->update_nodes == NULL)
1061     read_update_information_graph (namespace);
1062   if (namespace->update_nodes == NULL)
1063   {
1064 #if DEBUG_NAMESPACE
1065     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1066                 "No updateable nodes found for ID `%s'\n", next_id);
1067 #endif
1068     return;                     /* no nodes */
1069   }
1070   if (namespace->update_map == NULL)
1071   {
1072     /* need to construct */
1073     namespace->update_map =
1074         GNUNET_CONTAINER_multihashmap_create (2 +
1075                                               3 * namespace->update_node_count /
1076                                               4);
1077     for (i = 0; i < namespace->update_node_count; i++)
1078     {
1079       nsn = namespace->update_nodes[i];
1080       GNUNET_CRYPTO_hash (nsn->id, strlen (nsn->id), &hc);
1081       GNUNET_CONTAINER_multihashmap_put (namespace->update_map, &hc, nsn,
1082                                          GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1083     }
1084   }
1085   if (next_id != NULL)
1086   {
1087     GNUNET_CRYPTO_hash (next_id, strlen (next_id), &hc);
1088     pc.ip = ip;
1089     pc.ip_cls = ip_cls;
1090     GNUNET_CONTAINER_multihashmap_get_multiple (namespace->update_map, &hc,
1091                                                 &process_update_node, &pc);
1092     return;
1093   }
1094 #if DEBUG_NAMESPACE
1095   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1096               "Calculating TREEs to find roots of update trees\n");
1097 #endif
1098   /* Find heads of TREEs in update graph */
1099   nug = ++namespace->nug_gen;
1100   fc.tree_array = NULL;
1101   fc.tree_array_size = 0;
1102
1103   for (i = 0; i < namespace->update_node_count; i++)
1104   {
1105     nsn = namespace->update_nodes[i];
1106     if (nsn->nug == nug)
1107     {
1108 #if DEBUG_NAMESPACE
1109       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TREE of node `%s' is %u\n", nsn->id,
1110                   nsn->nug);
1111 #endif
1112       continue;                 /* already placed in TREE */
1113     }
1114     GNUNET_CRYPTO_hash (nsn->update, strlen (nsn->update), &hc);
1115     nsn->nug = nug;
1116     nsn->tree_id = UINT_MAX;
1117     fc.id = UINT_MAX;
1118     fc.nug = nug;
1119     fc.namespace = namespace;
1120     GNUNET_CONTAINER_multihashmap_get_multiple (namespace->update_map, &hc,
1121                                                 &find_trees, &fc);
1122     if (fc.id == UINT_MAX)
1123     {
1124       /* start new TREE */
1125       for (fc.id = 0; fc.id < fc.tree_array_size; fc.id++)
1126       {
1127         if (fc.tree_array[fc.id] == NULL)
1128         {
1129           fc.tree_array[fc.id] = nsn;
1130           nsn->tree_id = fc.id;
1131           break;
1132         }
1133       }
1134       if (fc.id == fc.tree_array_size)
1135       {
1136         GNUNET_array_append (fc.tree_array, fc.tree_array_size, nsn);
1137         nsn->tree_id = fc.id;
1138       }
1139 #if DEBUG_NAMESPACE
1140       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1141                   "Starting new TREE %u with node `%s'\n", nsn->tree_id,
1142                   nsn->id);
1143 #endif
1144       /* put all nodes with same identifier into this TREE */
1145       GNUNET_CRYPTO_hash (nsn->id, strlen (nsn->id), &hc);
1146       fc.id = nsn->tree_id;
1147       fc.nug = nug;
1148       fc.namespace = namespace;
1149       GNUNET_CONTAINER_multihashmap_get_multiple (namespace->update_map, &hc,
1150                                                   &find_trees, &fc);
1151     }
1152     else
1153     {
1154       /* make head of TREE "id" */
1155       fc.tree_array[fc.id] = nsn;
1156       nsn->tree_id = fc.id;
1157     }
1158 #if DEBUG_NAMESPACE
1159     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TREE of node `%s' is %u\n", nsn->id,
1160                 fc.id);
1161 #endif
1162   }
1163   for (i = 0; i < fc.tree_array_size; i++)
1164   {
1165     nsn = fc.tree_array[i];
1166     if (NULL != nsn)
1167     {
1168 #if DEBUG_NAMESPACE
1169       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Root of TREE %u is node `%s'\n", i,
1170                   nsn->id);
1171 #endif
1172
1173       ip (ip_cls, nsn->id, nsn->uri, nsn->md, nsn->update);
1174     }
1175   }
1176   GNUNET_array_grow (fc.tree_array, fc.tree_array_size, 0);
1177 #if DEBUG_NAMESPACE
1178   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Done processing TREEs\n");
1179 #endif
1180 }
1181
1182
1183 /* end of fs_namespace.c */