2 This file is part of GNUnet
3 Copyright (C) 2003-2013 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
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 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
22 * @file fs/fs_namespace.c
23 * @brief publishing to namespaces, and tracking updateable entries
25 * @author Christian Grothoff
28 #include "gnunet_constants.h"
29 #include "gnunet_signatures.h"
30 #include "gnunet_util_lib.h"
31 #include "gnunet_fs_service.h"
33 #include "fs_publish_ublock.h"
37 * Information about an (updateable) node in the
40 struct NamespaceUpdateNode {
42 * Identifier for this node.
47 * Identifier of children of this node.
52 * Metadata for this entry.
54 struct GNUNET_CONTAINER_MetaData *md;
57 * URI of this entry in the namespace.
59 struct GNUNET_FS_Uri *uri;
62 * Namespace update generation ID. Used to ensure
63 * freshness of the tree_id.
68 * TREE this entry belongs to (if nug is current).
75 * Handle to update information for a namespace.
77 struct GNUNET_FS_UpdateInformationGraph {
79 * Handle to the FS service context.
81 struct GNUNET_FS_Handle *h;
84 * Array with information about nodes in the namespace.
86 struct NamespaceUpdateNode **update_nodes;
89 * Private key for the namespace.
91 struct GNUNET_CRYPTO_EcdsaPrivateKey ns;
94 * Hash map mapping identifiers of update nodes
95 * to the update nodes (initialized on-demand).
97 struct GNUNET_CONTAINER_MultiHashMap *update_map;
100 * Size of the update nodes array.
102 unsigned int update_node_count;
110 * Generator for unique nug numbers.
112 unsigned int nug_gen;
117 * Return the name of the directory in which we store
118 * the update information graph for the given local namespace.
120 * @param h file-sharing handle
121 * @param ns namespace handle
122 * @return NULL on error, otherwise the name of the directory
125 get_update_information_directory(
126 struct GNUNET_FS_Handle *h,
127 const struct GNUNET_CRYPTO_EcdsaPrivateKey *ns)
131 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
132 struct GNUNET_HashCode hc;
133 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
136 GNUNET_CONFIGURATION_get_value_filename(h->cfg, "FS", "UPDATE_DIR", &dn))
138 GNUNET_log_config_missing(GNUNET_ERROR_TYPE_ERROR, "fs", "UPDATE_DIR");
141 GNUNET_CRYPTO_ecdsa_key_get_public(ns, &pub);
142 GNUNET_CRYPTO_hash(&pub, sizeof(pub), &hc);
143 GNUNET_CRYPTO_hash_to_enc(&hc, &enc);
144 GNUNET_asprintf(&ret,
148 (const char *)enc.encoding);
155 * Release memory occupied by UIG datastructure.
157 * @param uig data structure to free
160 free_update_information_graph(struct GNUNET_FS_UpdateInformationGraph *uig)
163 struct NamespaceUpdateNode *nsn;
165 for (i = 0; i < uig->update_node_count; i++)
167 nsn = uig->update_nodes[i];
168 GNUNET_CONTAINER_meta_data_destroy(nsn->md);
169 GNUNET_FS_uri_destroy(nsn->uri);
170 GNUNET_free(nsn->id);
171 GNUNET_free(nsn->update);
174 GNUNET_array_grow(uig->update_nodes, uig->update_node_count, 0);
175 if (NULL != uig->update_map)
176 GNUNET_CONTAINER_multihashmap_destroy(uig->update_map);
182 * Write a namespace's update node graph to a file.
184 * @param uig update information graph to dump
187 write_update_information_graph(struct GNUNET_FS_UpdateInformationGraph *uig)
190 struct GNUNET_BIO_WriteHandle *wh;
192 struct NamespaceUpdateNode *n;
195 fn = get_update_information_directory(uig->h, &uig->ns);
196 wh = GNUNET_BIO_write_open(fn);
199 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
200 _("Failed to open `%s' for writing: %s\n"),
206 if (GNUNET_OK != GNUNET_BIO_write_int32(wh, uig->update_node_count))
208 for (i = 0; i < uig->update_node_count; i++)
210 n = uig->update_nodes[i];
211 uris = GNUNET_FS_uri_to_string(n->uri);
212 if ((GNUNET_OK != GNUNET_BIO_write_string(wh, n->id)) ||
213 (GNUNET_OK != GNUNET_BIO_write_meta_data(wh, n->md)) ||
214 (GNUNET_OK != GNUNET_BIO_write_string(wh, n->update)) ||
215 (GNUNET_OK != GNUNET_BIO_write_string(wh, uris)))
223 if (GNUNET_OK != GNUNET_BIO_write_close(wh))
224 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
225 _("Failed to write `%s': %s\n"),
233 * Read the namespace update node graph from a file.
235 * @param h FS handle to use
236 * @param ns namespace to read
237 * @return update graph, never NULL
239 static struct GNUNET_FS_UpdateInformationGraph *
240 read_update_information_graph(struct GNUNET_FS_Handle *h,
241 const struct GNUNET_CRYPTO_EcdsaPrivateKey *ns)
243 struct GNUNET_FS_UpdateInformationGraph *uig;
245 struct GNUNET_BIO_ReadHandle *rh;
247 struct NamespaceUpdateNode *n;
252 uig = GNUNET_new(struct GNUNET_FS_UpdateInformationGraph);
255 fn = get_update_information_directory(h, ns);
256 if (GNUNET_YES != GNUNET_DISK_file_test(fn))
261 rh = GNUNET_BIO_read_open(fn);
267 if (GNUNET_OK != GNUNET_BIO_read_int32(rh, &count))
272 if (count > 1024 * 1024)
280 GNUNET_malloc(count * sizeof(struct NamespaceUpdateNode *));
282 for (i = 0; i < count; i++)
284 n = GNUNET_new(struct NamespaceUpdateNode);
286 GNUNET_BIO_read_string(rh, "identifier", &n->id, 1024)) ||
287 (GNUNET_OK != GNUNET_BIO_read_meta_data(rh, "meta", &n->md)) ||
289 GNUNET_BIO_read_string(rh, "update-id", &n->update, 1024)) ||
290 (GNUNET_OK != GNUNET_BIO_read_string(rh, "uri", &uris, 1024 * 2)))
293 GNUNET_free_non_null(n->id);
294 GNUNET_free_non_null(n->update);
296 GNUNET_CONTAINER_meta_data_destroy(n->md);
300 n->uri = GNUNET_FS_uri_parse(uris, &emsg);
307 GNUNET_free_non_null(n->update);
308 GNUNET_CONTAINER_meta_data_destroy(n->md);
312 uig->update_nodes[i] = n;
314 uig->update_node_count = i;
316 if (GNUNET_OK != GNUNET_BIO_read_close(rh, &emsg))
318 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
319 _("Failed to read `%s': %s\n"),
330 * Context for the SKS publication.
332 struct GNUNET_FS_PublishSksContext {
334 * URI of the new entry in the namespace.
336 struct GNUNET_FS_Uri *uri;
339 * Namespace update node to add to namespace on success (or to be
340 * deleted if publishing failed).
342 struct NamespaceUpdateNode *nsn;
345 * Namespace we're publishing to.
347 struct GNUNET_CRYPTO_EcdsaPrivateKey ns;
350 * Handle to the datastore.
352 struct GNUNET_DATASTORE_Handle *dsh;
357 struct GNUNET_FS_Handle *h;
360 * Function to call once we're done.
362 GNUNET_FS_PublishContinuation cont;
370 * Handle for our UBlock operation request.
372 struct GNUNET_FS_PublishUblockContext *uc;
377 * Function called by the UBlock construction with
378 * the result from the PUT (UBlock) request.
380 * @param cls closure of type "struct GNUNET_FS_PublishSksContext*"
381 * @param msg error message (or NULL)
384 sks_publish_cont(void *cls, const char *msg)
386 struct GNUNET_FS_PublishSksContext *psc = cls;
387 struct GNUNET_FS_UpdateInformationGraph *uig;
392 if (NULL != psc->cont)
393 psc->cont(psc->cont_cls, NULL, msg);
394 GNUNET_FS_publish_sks_cancel(psc);
397 if (NULL != psc->nsn)
399 /* FIXME: this can be done much more
400 * efficiently by simply appending to the
401 * file and overwriting the 4-byte header */
402 uig = read_update_information_graph(psc->h, &psc->ns);
403 GNUNET_array_append(uig->update_nodes, uig->update_node_count, psc->nsn);
405 write_update_information_graph(uig);
406 free_update_information_graph(uig);
408 if (NULL != psc->cont)
409 psc->cont(psc->cont_cls, psc->uri, NULL);
410 GNUNET_FS_publish_sks_cancel(psc);
415 * Publish an SBlock on GNUnet.
417 * @param h handle to the file sharing subsystem
418 * @param ns namespace to publish in
419 * @param identifier identifier to use
420 * @param update update identifier to use
421 * @param meta metadata to use
422 * @param uri URI to refer to in the SBlock
423 * @param bo block options
424 * @param options publication options
425 * @param cont continuation
426 * @param cont_cls closure for cont
427 * @return NULL on error ('cont' will still be called)
429 struct GNUNET_FS_PublishSksContext *
430 GNUNET_FS_publish_sks(struct GNUNET_FS_Handle *h,
431 const struct GNUNET_CRYPTO_EcdsaPrivateKey *ns,
432 const char *identifier,
434 const struct GNUNET_CONTAINER_MetaData *meta,
435 const struct GNUNET_FS_Uri *uri,
436 const struct GNUNET_FS_BlockOptions *bo,
437 enum GNUNET_FS_PublishOptions options,
438 GNUNET_FS_PublishContinuation cont,
441 struct GNUNET_FS_PublishSksContext *psc;
442 struct GNUNET_FS_Uri *sks_uri;
444 sks_uri = GNUNET_new(struct GNUNET_FS_Uri);
445 sks_uri->type = GNUNET_FS_URI_SKS;
446 sks_uri->data.sks.identifier = GNUNET_strdup(identifier);
447 GNUNET_CRYPTO_ecdsa_key_get_public(ns, &sks_uri->data.sks.ns);
449 psc = GNUNET_new(struct GNUNET_FS_PublishSksContext);
453 psc->cont_cls = cont_cls;
455 if (0 == (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
457 psc->dsh = GNUNET_DATASTORE_connect(h->cfg);
458 if (NULL == psc->dsh)
460 sks_publish_cont(psc, _("Failed to connect to datastore."));
466 psc->nsn = GNUNET_new(struct NamespaceUpdateNode);
467 psc->nsn->id = GNUNET_strdup(identifier);
468 psc->nsn->update = GNUNET_strdup(update);
469 psc->nsn->md = GNUNET_CONTAINER_meta_data_duplicate(meta);
470 psc->nsn->uri = GNUNET_FS_uri_dup(uri);
472 psc->uc = GNUNET_FS_publish_ublock_(h,
488 * Abort the SKS publishing operation.
490 * @param psc context of the operation to abort.
493 GNUNET_FS_publish_sks_cancel(struct GNUNET_FS_PublishSksContext *psc)
497 GNUNET_FS_publish_ublock_cancel_(psc->uc);
500 if (NULL != psc->dsh)
502 GNUNET_DATASTORE_disconnect(psc->dsh, GNUNET_NO);
505 GNUNET_FS_uri_destroy(psc->uri);
506 if (NULL != psc->nsn)
508 GNUNET_CONTAINER_meta_data_destroy(psc->nsn->md);
509 GNUNET_FS_uri_destroy(psc->nsn->uri);
510 GNUNET_free(psc->nsn->id);
511 GNUNET_free(psc->nsn->update);
512 GNUNET_free(psc->nsn);
519 * Closure for 'process_update_node'.
521 struct ProcessUpdateClosure {
523 * Function to call for each node.
525 GNUNET_FS_IdentifierProcessor ip;
535 * Call the iterator in the closure for each node.
537 * @param cls closure (of type 'struct ProcessUpdateClosure *')
538 * @param key current key code
539 * @param value value in the hash map (of type 'struct NamespaceUpdateNode *')
540 * @return GNUNET_YES if we should continue to
545 process_update_node(void *cls, const struct GNUNET_HashCode *key, void *value)
547 struct ProcessUpdateClosure *pc = cls;
548 struct NamespaceUpdateNode *nsn = value;
550 pc->ip(pc->ip_cls, nsn->id, nsn->uri, nsn->md, nsn->update);
556 * Closure for 'find_trees'.
558 struct FindTreeClosure {
560 * UIG we are operating on.
562 struct GNUNET_FS_UpdateInformationGraph *uig;
565 * Array with 'head's of TREEs.
567 struct NamespaceUpdateNode **tree_array;
570 * Size of 'tree_array'
572 unsigned int tree_array_size;
575 * Current generational ID used.
580 * Identifier for the current TREE, or UINT_MAX for none yet.
587 * Find all nodes reachable from the current node (including the
588 * current node itself). If they are in no tree, add them to the
589 * current one. If they are the head of another tree, merge the
590 * trees. If they are in the middle of another tree, let them be.
591 * We can tell that a node is already in an tree by checking if
592 * its 'nug' field is set to the current 'nug' value. It is the
593 * head of an tree if it is in the 'tree_array' under its respective
596 * In short, we're trying to find the smallest number of tree to
597 * cover a directed graph.
599 * @param cls closure (of type 'struct FindTreeClosure')
600 * @param key current key code
601 * @param value value in the hash map
602 * @return GNUNET_YES if we should continue to
607 find_trees(void *cls, const struct GNUNET_HashCode *key, void *value)
609 struct FindTreeClosure *fc = cls;
610 struct NamespaceUpdateNode *nsn = value;
611 struct GNUNET_HashCode hc;
613 if (nsn->nug == fc->nug)
615 if (UINT_MAX == nsn->tree_id)
616 return GNUNET_YES; /* circular */
617 GNUNET_assert(nsn->tree_id < fc->tree_array_size);
618 if (fc->tree_array[nsn->tree_id] != nsn)
619 return GNUNET_YES; /* part of "another" (directed) TREE,
620 * and not root of it, end trace */
621 if (nsn->tree_id == fc->id)
622 return GNUNET_YES; /* that's our own root (can this be?) */
623 /* merge existing TREE, we have a root for both */
624 fc->tree_array[nsn->tree_id] = NULL;
625 if (UINT_MAX == fc->id)
626 fc->id = nsn->tree_id; /* take over ID */
631 nsn->tree_id = UINT_MAX; /* mark as undef */
633 GNUNET_CRYPTO_hash(nsn->update, strlen(nsn->update), &hc);
634 GNUNET_CONTAINER_multihashmap_get_multiple(fc->uig->update_map,
644 * List all of the identifiers in the namespace for which we could
645 * produce an update. Namespace updates form a graph where each node
646 * has a name. Each node can have any number of URI/meta-data entries
647 * which can each be linked to other nodes. Cycles are possible.
649 * Calling this function with "next_id" NULL will cause the library to
650 * call "ip" with a root for each strongly connected component of the
651 * graph (a root being a node from which all other nodes in the Tree
654 * Calling this function with "next_id" being the name of a node will
655 * cause the library to call "ip" with all children of the node. Note
656 * that cycles within the final tree are possible (including self-loops).
657 * I know, odd definition of a tree, but the GUI will display an actual
658 * tree (GtkTreeView), so that's what counts for the term here.
660 * @param h fs handle to use
661 * @param ns namespace to inspect for updateable content
662 * @param next_id ID to look for; use NULL to look for tree roots
663 * @param ip function to call on each updateable identifier
664 * @param ip_cls closure for ip
667 GNUNET_FS_namespace_list_updateable(
668 struct GNUNET_FS_Handle *h,
669 const struct GNUNET_CRYPTO_EcdsaPrivateKey *ns,
671 GNUNET_FS_IdentifierProcessor ip,
676 struct GNUNET_HashCode hc;
677 struct NamespaceUpdateNode *nsn;
678 struct ProcessUpdateClosure pc;
679 struct FindTreeClosure fc;
680 struct GNUNET_FS_UpdateInformationGraph *uig;
682 uig = read_update_information_graph(h, ns);
683 if (NULL == uig->update_nodes)
685 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
686 "No updateable nodes found for ID `%s'\n",
688 free_update_information_graph(uig);
689 return; /* no nodes */
692 GNUNET_CONTAINER_multihashmap_create(2 + 3 * uig->update_node_count / 4,
694 for (i = 0; i < uig->update_node_count; i++)
696 nsn = uig->update_nodes[i];
697 GNUNET_CRYPTO_hash(nsn->id, strlen(nsn->id), &hc);
698 GNUNET_CONTAINER_multihashmap_put(
702 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
706 GNUNET_CRYPTO_hash(next_id, strlen(next_id), &hc);
709 GNUNET_CONTAINER_multihashmap_get_multiple(uig->update_map,
711 &process_update_node,
713 free_update_information_graph(uig);
716 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
717 "Calculating TREEs to find roots of update trees\n");
718 /* Find heads of TREEs in update graph */
719 nug = ++uig->nug_gen;
720 fc.tree_array = NULL;
721 fc.tree_array_size = 0;
723 for (i = 0; i < uig->update_node_count; i++)
725 nsn = uig->update_nodes[i];
728 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
729 "TREE of node `%s' is %u\n",
732 continue; /* already placed in TREE */
734 GNUNET_CRYPTO_hash(nsn->update, strlen(nsn->update), &hc);
736 nsn->tree_id = UINT_MAX;
740 GNUNET_CONTAINER_multihashmap_get_multiple(uig->update_map,
744 if (UINT_MAX == fc.id)
747 for (fc.id = 0; fc.id < fc.tree_array_size; fc.id++)
749 if (NULL == fc.tree_array[fc.id])
751 fc.tree_array[fc.id] = nsn;
752 nsn->tree_id = fc.id;
756 if (fc.id == fc.tree_array_size)
758 GNUNET_array_append(fc.tree_array, fc.tree_array_size, nsn);
759 nsn->tree_id = fc.id;
761 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
762 "Starting new TREE %u with node `%s'\n",
765 /* put all nodes with same identifier into this TREE */
766 GNUNET_CRYPTO_hash(nsn->id, strlen(nsn->id), &hc);
767 fc.id = nsn->tree_id;
770 GNUNET_CONTAINER_multihashmap_get_multiple(uig->update_map,
777 /* make head of TREE "id" */
778 fc.tree_array[fc.id] = nsn;
779 nsn->tree_id = fc.id;
781 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
782 "TREE of node `%s' is %u\n",
786 for (i = 0; i < fc.tree_array_size; i++)
788 nsn = fc.tree_array[i];
791 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
792 "Root of TREE %u is node `%s'\n",
795 ip(ip_cls, nsn->id, nsn->uri, nsn->md, nsn->update);
798 GNUNET_array_grow(fc.tree_array, fc.tree_array_size, 0);
799 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Done processing TREEs\n");
800 free_update_information_graph(uig);
804 /* end of fs_namespace.c */