aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO4
-rw-r--r--src/fs/fs.h67
-rw-r--r--src/fs/fs_namespace.c732
-rw-r--r--src/fs/fs_publish.c219
4 files changed, 795 insertions, 227 deletions
diff --git a/TODO b/TODO
index b10364d43..d5cc48d16 100644
--- a/TODO
+++ b/TODO
@@ -17,8 +17,6 @@
17 - derived key generation [Nils] 17 - derived key generation [Nils]
18* PWNAT: [Nate/MW/Nils] 18* PWNAT: [Nate/MW/Nils]
19 - W32 port 19 - W32 port
20* FS: [CG]
21 - implement 'GNUNET_FS_namespace_list_updateable', reconsider API!
22* GNUNET-GTK: [CG] 20* GNUNET-GTK: [CG]
23 - namespaces: 21 - namespaces:
24 + namespace publishing 22 + namespace publishing
@@ -34,8 +32,6 @@
34 + handle 'lost parent' case for recursive downloads (need to move children!) 32 + handle 'lost parent' case for recursive downloads (need to move children!)
35 + clean up TreeStores in main_window_file_publish on dialog close 33 + clean up TreeStores in main_window_file_publish on dialog close
36 + clean up ListStores in main_window_adv_pseudonym 34 + clean up ListStores in main_window_adv_pseudonym
37* DATASTORE:
38 - modify testcases to not fail if database is not configured (i.e. 'mysqlcheck' DB does not exist)
39 35
400.9.0pre3: 360.9.0pre3:
41* Determine RC bugs and fix those! 37* Determine RC bugs and fix those!
diff --git a/src/fs/fs.h b/src/fs/fs.h
index 41831e8a8..699f73a79 100644
--- a/src/fs/fs.h
+++ b/src/fs/fs.h
@@ -1839,15 +1839,72 @@ struct GNUNET_FS_DownloadContext
1839 int tried_full_data; 1839 int tried_full_data;
1840}; 1840};
1841 1841
1842
1843/**
1844 * Information about an (updateable) node in the
1845 * namespace.
1846 */
1847struct NamespaceUpdateNode
1848{
1849 /**
1850 * Identifier for this node.
1851 */
1852 char *id;
1853
1854 /**
1855 * Identifier of children of this node.
1856 */
1857 char *update;
1858
1859 /**
1860 * Metadata for this entry.
1861 */
1862 struct GNUNET_CONTAINER_MetaData *md;
1863
1864 /**
1865 * URI of this entry in the namespace.
1866 */
1867 struct GNUNET_FS_Uri *uri;
1868
1869 /**
1870 * Namespace update generation ID. Used to ensure
1871 * freshness of the scc_id.
1872 */
1873 unsigned int nug;
1874
1875 /**
1876 * SCC this entry belongs to (if nug is current).
1877 */
1878 unsigned int scc_id;
1879
1880};
1881
1882
1842struct GNUNET_FS_Namespace 1883struct GNUNET_FS_Namespace
1843{ 1884{
1844 1885
1845 /** 1886 /**
1887 * Handle to the FS service context.
1888 */
1889 struct GNUNET_FS_Handle *h;
1890
1891 /**
1892 * Array with information about nodes in the namespace.
1893 */
1894 struct NamespaceUpdateNode **update_nodes;
1895
1896 /**
1846 * Private key for the namespace. 1897 * Private key for the namespace.
1847 */ 1898 */
1848 struct GNUNET_CRYPTO_RsaPrivateKey *key; 1899 struct GNUNET_CRYPTO_RsaPrivateKey *key;
1849 1900
1850 /** 1901 /**
1902 * Hash map mapping identifiers of update nodes
1903 * to the update nodes (initialized on-demand).
1904 */
1905 struct GNUNET_CONTAINER_MultiHashMap *update_map;
1906
1907 /**
1851 * Name of the file with the private key. 1908 * Name of the file with the private key.
1852 */ 1909 */
1853 char *filename; 1910 char *filename;
@@ -1858,9 +1915,19 @@ struct GNUNET_FS_Namespace
1858 char *name; 1915 char *name;
1859 1916
1860 /** 1917 /**
1918 * Size of the update nodes array.
1919 */
1920 unsigned int update_node_count;
1921
1922 /**
1861 * Reference counter. 1923 * Reference counter.
1862 */ 1924 */
1863 unsigned int rc; 1925 unsigned int rc;
1926
1927 /**
1928 * Generator for unique nug numbers.
1929 */
1930 unsigned int nug_gen;
1864}; 1931};
1865 1932
1866 1933
diff --git a/src/fs/fs_namespace.c b/src/fs/fs_namespace.c
index ee3743733..a9bcaf8e5 100644
--- a/src/fs/fs_namespace.c
+++ b/src/fs/fs_namespace.c
@@ -59,6 +59,184 @@ get_namespace_directory (struct GNUNET_FS_Handle *h)
59 59
60 60
61/** 61/**
62 * Return the name of the directory in which we store
63 * the update information graph for the given local namespace.
64 *
65 * @param ns namespace handle
66 * @return NULL on error, otherwise the name of the directory
67 */
68static char *
69get_update_information_directory (struct GNUNET_FS_Namespace *ns)
70{
71 char *dn;
72 char *ret;
73
74 if (GNUNET_OK !=
75 GNUNET_CONFIGURATION_get_value_filename (ns->h->cfg,
76 "FS",
77 "UPDATE_DIR",
78 &dn))
79 {
80 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
81 _("Configuration fails to specify `%s' in section `%s'\n"),
82 "UPDATE_DIR",
83 "fs");
84 return NULL;
85 }
86 GNUNET_asprintf (&ret,
87 "%s%s%s",
88 dn,
89 DIR_SEPARATOR_STR,
90 ns->name);
91 GNUNET_free (dn);
92 return ret;
93}
94
95
96/**
97 * Write the namespace update node graph to a file.
98 *
99 * @param ns namespace to dump
100 */
101static void
102write_update_information_graph (struct GNUNET_FS_Namespace *ns)
103{
104 char * fn;
105 struct GNUNET_BIO_WriteHandle *wh;
106 unsigned int i;
107 struct NamespaceUpdateNode *n;
108 char *uris;
109
110 fn = get_update_information_directory (ns);
111 wh = GNUNET_BIO_write_open (fn);
112 if (wh == NULL)
113 {
114 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
115 _("Failed to open `%s' for writing: %s\n"),
116 STRERROR (errno));
117 GNUNET_free (fn);
118 return;
119 }
120 if (GNUNET_OK !=
121 GNUNET_BIO_write_int32 (wh, ns->update_node_count))
122 goto END;
123 for (i=0;i<ns->update_node_count;i++)
124 {
125 n = ns->update_nodes[i];
126 uris = GNUNET_FS_uri_to_string (n->uri);
127 if ( (GNUNET_OK !=
128 GNUNET_BIO_write_string (wh, n->id)) ||
129 (GNUNET_OK !=
130 GNUNET_BIO_write_meta_data (wh, n->md)) ||
131 (GNUNET_OK !=
132 GNUNET_BIO_write_string (wh, n->update)) ||
133 (GNUNET_OK !=
134 GNUNET_BIO_write_string (wh, uris)) )
135 {
136 GNUNET_free (uris);
137 break;
138 }
139 GNUNET_free (uris);
140 }
141 END:
142 if (GNUNET_OK != GNUNET_BIO_write_close (wh))
143 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
144 _("Failed to write `%s': %s\n"),
145 STRERROR (errno));
146 GNUNET_free (fn);
147}
148
149
150/**
151 * Read the namespace update node graph from a file.
152 *
153 * @param ns namespace to read
154 */
155static void
156read_update_information_graph (struct GNUNET_FS_Namespace *ns)
157{
158 char * fn;
159 struct GNUNET_BIO_ReadHandle *rh;
160 unsigned int i;
161 struct NamespaceUpdateNode *n;
162 char *uris;
163 uint32_t count;
164 char *emsg;
165
166 fn = get_update_information_directory (ns);
167 rh = GNUNET_BIO_read_open (fn);
168 if (rh == NULL)
169 {
170 GNUNET_free (fn);
171 return;
172 }
173 if (GNUNET_OK !=
174 GNUNET_BIO_read_int32 (rh, &count))
175 {
176 GNUNET_break (0);
177 goto END;
178 }
179 if (count > 1024 * 1024)
180 {
181 GNUNET_break (0);
182 goto END;
183 }
184 if (count == 0)
185 {
186 GNUNET_break (GNUNET_OK == GNUNET_BIO_read_close (rh, NULL));
187 GNUNET_free (fn);
188 return;
189 }
190 ns->update_nodes = GNUNET_malloc (count * sizeof (struct NamespaceUpdateNode*));
191
192 for (i=0;i<count;i++)
193 {
194 n = GNUNET_malloc (sizeof (struct NamespaceUpdateNode));
195 if ( (GNUNET_OK !=
196 GNUNET_BIO_read_string (rh, "identifier", &n->id, 1024)) ||
197 (GNUNET_OK !=
198 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 !=
202 GNUNET_BIO_read_string (rh, "uri", &uris, 1024 * 2)) )
203 {
204 GNUNET_break (0);
205 GNUNET_free_non_null (n->id);
206 GNUNET_free_non_null (n->update);
207 if (n->md != NULL)
208 GNUNET_CONTAINER_meta_data_destroy (n->md);
209 GNUNET_free (n);
210 break;
211 }
212 n->uri = GNUNET_FS_uri_parse (uris, &emsg);
213 GNUNET_free (uris);
214 if (n->uri == NULL)
215 {
216 GNUNET_break (0);
217 GNUNET_free (emsg);
218 GNUNET_free (n->id);
219 GNUNET_free (n->update);
220 GNUNET_CONTAINER_meta_data_destroy (n->md);
221 GNUNET_free (n);
222 break;
223 }
224 ns->update_nodes[i] = n;
225 }
226 ns->update_node_count = i;
227 END:
228 if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))
229 {
230 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
231 _("Failed to write `%s': %s\n"),
232 emsg);
233 GNUNET_free (emsg);
234 }
235 GNUNET_free (fn);
236}
237
238
239/**
62 * Context for advertising a namespace. 240 * Context for advertising a namespace.
63 */ 241 */
64struct AdvertisementContext 242struct AdvertisementContext
@@ -363,6 +541,7 @@ GNUNET_FS_namespace_create (struct GNUNET_FS_Handle *h,
363 name); 541 name);
364 GNUNET_free (dn); 542 GNUNET_free (dn);
365 ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Namespace)); 543 ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Namespace));
544 ret->h = h;
366 ret->rc = 1; 545 ret->rc = 1;
367 ret->key = GNUNET_CRYPTO_rsa_key_create_from_file (fn); 546 ret->key = GNUNET_CRYPTO_rsa_key_create_from_file (fn);
368 if (ret->key == NULL) 547 if (ret->key == NULL)
@@ -395,6 +574,9 @@ int
395GNUNET_FS_namespace_delete (struct GNUNET_FS_Namespace *namespace, 574GNUNET_FS_namespace_delete (struct GNUNET_FS_Namespace *namespace,
396 int freeze) 575 int freeze)
397{ 576{
577 unsigned int i;
578 struct NamespaceUpdateNode *nsn;
579
398 namespace->rc--; 580 namespace->rc--;
399 if (freeze) 581 if (freeze)
400 { 582 {
@@ -408,6 +590,20 @@ GNUNET_FS_namespace_delete (struct GNUNET_FS_Namespace *namespace,
408 GNUNET_CRYPTO_rsa_key_free (namespace->key); 590 GNUNET_CRYPTO_rsa_key_free (namespace->key);
409 GNUNET_free (namespace->filename); 591 GNUNET_free (namespace->filename);
410 GNUNET_free (namespace->name); 592 GNUNET_free (namespace->name);
593 for (i=0;i<namespace->update_node_count;i++)
594 {
595 nsn = namespace->update_nodes[i];
596 GNUNET_CONTAINER_meta_data_destroy (nsn->md);
597 GNUNET_FS_uri_destroy (nsn->uri);
598 GNUNET_free (nsn->id);
599 GNUNET_free (nsn->update);
600 GNUNET_free (nsn);
601 }
602 GNUNET_array_grow (namespace->update_nodes,
603 namespace->update_node_count,
604 0);
605 if (namespace->update_map != NULL)
606 GNUNET_CONTAINER_multihashmap_destroy (namespace->update_map);
411 GNUNET_free (namespace); 607 GNUNET_free (namespace);
412 } 608 }
413 return GNUNET_OK; 609 return GNUNET_OK;
@@ -507,22 +703,550 @@ GNUNET_FS_namespace_list (struct GNUNET_FS_Handle *h,
507 703
508 704
509 705
706
510/** 707/**
511 * List all of the identifiers in the namespace for 708 * Context for the SKS publication.
512 * which we could produce an update. 709 */
710struct PublishSksContext
711{
712
713 /**
714 * URI of the new entry in the namespace.
715 */
716 struct GNUNET_FS_Uri *uri;
717
718 /**
719 * Namespace update node to add to namespace on success (or to be
720 * deleted if publishing failed).
721 */
722 struct NamespaceUpdateNode *nsn;
723
724 /**
725 * Namespace we're publishing to.
726 */
727 struct GNUNET_FS_Namespace *namespace;
728
729 /**
730 * Handle to the datastore.
731 */
732 struct GNUNET_DATASTORE_Handle *dsh;
733
734 /**
735 * Function to call once we're done.
736 */
737 GNUNET_FS_PublishContinuation cont;
738
739 /**
740 * Closure for cont.
741 */
742 void *cont_cls;
743
744};
745
746
747/**
748 * Function called by the datastore API with
749 * the result from the PUT (SBlock) request.
750 *
751 * @param cls closure of type "struct PublishSksContext*"
752 * @param success GNUNET_OK on success
753 * @param msg error message (or NULL)
754 */
755static void
756sb_put_cont (void *cls,
757 int success,
758 const char *msg)
759{
760 struct PublishSksContext *psc = cls;
761 GNUNET_HashCode hc;
762
763 if (NULL != psc->dsh)
764 {
765 GNUNET_DATASTORE_disconnect (psc->dsh, GNUNET_NO);
766 psc->dsh = NULL;
767 }
768 if (GNUNET_OK != success)
769 {
770 psc->cont (psc->cont_cls,
771 NULL,
772 msg);
773 }
774 else
775 {
776 if (psc->nsn != NULL)
777 {
778 /* FIXME: this can be done much more
779 efficiently by simply appending to the
780 file and overwriting the 4-byte header */
781 if (psc->namespace->update_nodes == NULL)
782 read_update_information_graph (psc->namespace);
783 GNUNET_array_append (psc->namespace->update_nodes,
784 psc->namespace->update_node_count,
785 psc->nsn);
786 if (psc->namespace->update_map != NULL)
787 {
788 GNUNET_CRYPTO_hash (psc->nsn->id,
789 strlen (psc->nsn->id),
790 &hc);
791 GNUNET_CONTAINER_multihashmap_put (psc->namespace->update_map,
792 &hc,
793 psc->nsn,
794 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
795 }
796 psc->nsn = NULL;
797 write_update_information_graph (psc->namespace);
798 }
799 psc->cont (psc->cont_cls,
800 psc->uri,
801 NULL);
802 }
803 GNUNET_FS_namespace_delete (psc->namespace,
804 GNUNET_NO);
805 GNUNET_FS_uri_destroy (psc->uri);
806 if (psc->nsn != NULL)
807 {
808 GNUNET_CONTAINER_meta_data_destroy (psc->nsn->md);
809 GNUNET_FS_uri_destroy (psc->nsn->uri);
810 GNUNET_free (psc->nsn->id);
811 GNUNET_free (psc->nsn->update);
812 GNUNET_free (psc->nsn);
813 }
814 GNUNET_free (psc);
815}
816
817
818/**
819 * Publish an SBlock on GNUnet.
820 *
821 * @param h handle to the file sharing subsystem
822 * @param namespace namespace to publish in
823 * @param identifier identifier to use
824 * @param update update identifier to use
825 * @param meta metadata to use
826 * @param uri URI to refer to in the SBlock
827 * @param expirationTime when the SBlock expires
828 * @param anonymity anonymity level for the SBlock
829 * @param priority priority for the SBlock
830 * @param options publication options
831 * @param cont continuation
832 * @param cont_cls closure for cont
833 */
834void
835GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h,
836 struct GNUNET_FS_Namespace *namespace,
837 const char *identifier,
838 const char *update,
839 const struct GNUNET_CONTAINER_MetaData *meta,
840 const struct GNUNET_FS_Uri *uri,
841 struct GNUNET_TIME_Absolute expirationTime,
842 uint32_t anonymity,
843 uint32_t priority,
844 enum GNUNET_FS_PublishOptions options,
845 GNUNET_FS_PublishContinuation cont,
846 void *cont_cls)
847{
848 struct PublishSksContext *psc;
849 struct GNUNET_CRYPTO_AesSessionKey sk;
850 struct GNUNET_CRYPTO_AesInitializationVector iv;
851 struct GNUNET_FS_Uri *sks_uri;
852 char *uris;
853 size_t size;
854 size_t slen;
855 size_t nidlen;
856 size_t idlen;
857 ssize_t mdsize;
858 struct SBlock *sb;
859 struct SBlock *sb_enc;
860 char *dest;
861 struct GNUNET_CONTAINER_MetaData *mmeta;
862 GNUNET_HashCode key; /* hash of thisId = key */
863 GNUNET_HashCode id; /* hash of hc = identifier */
864 GNUNET_HashCode query; /* id ^ nsid = DB query */
865
866 if (NULL == meta)
867 mmeta = GNUNET_CONTAINER_meta_data_create ();
868 else
869 mmeta = GNUNET_CONTAINER_meta_data_duplicate (meta);
870 uris = GNUNET_FS_uri_to_string (uri);
871 slen = strlen (uris) + 1;
872 idlen = strlen (identifier);
873 if (update == NULL)
874 update = "";
875 nidlen = strlen (update) + 1;
876 mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (mmeta);
877 size = sizeof (struct SBlock) + slen + nidlen + mdsize;
878 if (size > MAX_SBLOCK_SIZE)
879 {
880 size = MAX_SBLOCK_SIZE;
881 mdsize = size - (sizeof (struct SBlock) + slen + nidlen);
882 }
883 sb = GNUNET_malloc (sizeof (struct SBlock) + size);
884 dest = (char *) &sb[1];
885 memcpy (dest, update, nidlen);
886 dest += nidlen;
887 memcpy (dest, uris, slen);
888 GNUNET_free (uris);
889 dest += slen;
890 mdsize = GNUNET_CONTAINER_meta_data_serialize (mmeta,
891 &dest,
892 mdsize,
893 GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
894 GNUNET_CONTAINER_meta_data_destroy (mmeta);
895 if (mdsize == -1)
896 {
897 GNUNET_break (0);
898 GNUNET_free (sb);
899 cont (cont_cls,
900 NULL,
901 _("Internal error."));
902 return;
903 }
904 size = sizeof (struct SBlock) + mdsize + slen + nidlen;
905 sb_enc = GNUNET_malloc (size);
906 GNUNET_CRYPTO_hash (identifier, idlen, &key);
907 GNUNET_CRYPTO_hash (&key, sizeof (GNUNET_HashCode), &id);
908 sks_uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri));
909 sks_uri->type = sks;
910 GNUNET_CRYPTO_rsa_key_get_public (namespace->key, &sb_enc->subspace);
911 GNUNET_CRYPTO_hash (&sb_enc->subspace,
912 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
913 &sks_uri->data.sks.namespace);
914 sks_uri->data.sks.identifier = GNUNET_strdup (identifier);
915 GNUNET_CRYPTO_hash_xor (&id,
916 &sks_uri->data.sks.namespace,
917 &sb_enc->identifier);
918 GNUNET_CRYPTO_hash_to_aes_key (&key, &sk, &iv);
919 GNUNET_CRYPTO_aes_encrypt (&sb[1],
920 size - sizeof (struct SBlock),
921 &sk,
922 &iv,
923 &sb_enc[1]);
924 sb_enc->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_SBLOCK);
925 sb_enc->purpose.size = htonl(slen + mdsize + nidlen
926 + sizeof(struct SBlock)
927 - sizeof(struct GNUNET_CRYPTO_RsaSignature));
928 GNUNET_assert (GNUNET_OK ==
929 GNUNET_CRYPTO_rsa_sign (namespace->key,
930 &sb_enc->purpose,
931 &sb_enc->signature));
932 psc = GNUNET_malloc (sizeof(struct PublishSksContext));
933 psc->uri = sks_uri;
934 psc->cont = cont;
935 psc->namespace = namespace;
936 namespace->rc++;
937 psc->cont_cls = cont_cls;
938 if (0 != (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
939 {
940 GNUNET_free (sb_enc);
941 GNUNET_free (sb);
942 sb_put_cont (psc,
943 GNUNET_OK,
944 NULL);
945 return;
946 }
947 psc->dsh = GNUNET_DATASTORE_connect (h->cfg, h->sched);
948 if (NULL == psc->dsh)
949 {
950 GNUNET_free (sb_enc);
951 GNUNET_free (sb);
952 sb_put_cont (psc,
953 GNUNET_NO,
954 _("Failed to connect to datastore."));
955 return;
956 }
957 GNUNET_CRYPTO_hash_xor (&sks_uri->data.sks.namespace,
958 &id,
959 &query);
960 if (NULL != update)
961 {
962 psc->nsn = GNUNET_malloc (sizeof (struct NamespaceUpdateNode));
963 psc->nsn->id = GNUNET_strdup (identifier);
964 psc->nsn->update = GNUNET_strdup (update);
965 psc->nsn->md = GNUNET_CONTAINER_meta_data_duplicate (meta);
966 psc->nsn->uri = GNUNET_FS_uri_dup (uri);
967 }
968 GNUNET_DATASTORE_put (psc->dsh,
969 0,
970 &sb_enc->identifier,
971 size,
972 sb_enc,
973 GNUNET_BLOCK_TYPE_SBLOCK,
974 priority,
975 anonymity,
976 expirationTime,
977 -2, 1,
978 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
979 &sb_put_cont,
980 psc);
981 GNUNET_free (sb);
982 GNUNET_free (sb_enc);
983}
984
985
986/**
987 * Closure for 'process_update_node'.
988 */
989struct ProcessUpdateClosure
990{
991 /**
992 * Function to call for each node.
993 */
994 GNUNET_FS_IdentifierProcessor ip;
995
996 /**
997 * Closure for 'ip'.
998 */
999 void *ip_cls;
1000};
1001
1002
1003/**
1004 * Call the iterator in the closure for each node.
1005 *
1006 * @param cls closure (of type 'struct ProcessUpdateClosure *')
1007 * @param key current key code
1008 * @param value value in the hash map (of type 'struct NamespaceUpdateNode *')
1009 * @return GNUNET_YES if we should continue to
1010 * iterate,
1011 * GNUNET_NO if not.
1012 */
1013static int
1014process_update_node (void *cls,
1015 const GNUNET_HashCode * key,
1016 void *value)
1017{
1018 struct ProcessUpdateClosure *pc = cls;
1019 struct NamespaceUpdateNode *nsn = value;
1020
1021 pc->ip (pc->ip_cls,
1022 nsn->id,
1023 nsn->uri,
1024 nsn->md,
1025 nsn->update);
1026 return GNUNET_YES;
1027}
1028
1029
1030/**
1031 * Closure for 'find_sccs'.
1032 */
1033struct FindSccClosure
1034{
1035 /**
1036 * Namespace we are operating on.
1037 */
1038 struct GNUNET_FS_Namespace *namespace;
1039
1040 /**
1041 * Array with 'head's of SCCs.
1042 */
1043 struct NamespaceUpdateNode **scc_array;
1044
1045 /**
1046 * Size of 'scc_array'
1047 */
1048 unsigned int scc_array_size;
1049
1050 /**
1051 * Current generational ID used.
1052 */
1053 unsigned int nug;
1054
1055 /**
1056 * Identifier for the current SCC, or UINT_MAX for none yet.
1057 */
1058 unsigned int id;
1059};
1060
1061
1062/**
1063 * Find all nodes reachable from the current node (including the
1064 * current node itself). If they are in no SCC, add them to the
1065 * current one. If they are the head of another SCC, merge the
1066 * SCCs. If they are in the middle of another SCC, let them be.
1067 * We can tell that a node is already in an SCC by checking if
1068 * its 'nug' field is set to the current 'nug' value. It is the
1069 * head of an SCC if it is in the 'scc_array' under its respective
1070 * 'scc_id'.
1071 *
1072 * @param cls closure (of type 'struct FindSccClosure')
1073 * @param key current key code
1074 * @param value value in the hash map
1075 * @return GNUNET_YES if we should continue to
1076 * iterate,
1077 * GNUNET_NO if not.
1078 */
1079static int
1080find_sccs (void *cls,
1081 const GNUNET_HashCode * key,
1082 void *value)
1083{
1084 struct FindSccClosure *fc = cls;
1085 struct NamespaceUpdateNode *nsn = value;
1086 GNUNET_HashCode hc;
1087
1088 if (nsn->nug == fc->nug)
1089 {
1090 if (fc->scc_array[nsn->scc_id] != nsn)
1091 return GNUNET_YES; /* part of another SCC, end trace */
1092 fc->scc_array[nsn->scc_id] = NULL;
1093 if (fc->id == UINT_MAX)
1094 fc->id = nsn->scc_id; /* take over ID */
1095 }
1096 else
1097 {
1098 nsn->nug = fc->nug;
1099 /* trace */
1100 GNUNET_CRYPTO_hash (nsn->update,
1101 strlen (nsn->update),
1102 &hc);
1103 GNUNET_CONTAINER_multihashmap_get_multiple (fc->namespace->update_map,
1104 &hc,
1105 &find_sccs,
1106 fc);
1107 }
1108 return GNUNET_YES;
1109}
1110
1111
1112/**
1113 * List all of the identifiers in the namespace for which we could
1114 * produce an update. Namespace updates form a graph where each node
1115 * has a name. Each node can have any number of URI/meta-data entries
1116 * which can each be linked to other nodes. Cycles are possible.
1117 *
1118 * Calling this function with "next_id" NULL will cause the library to
1119 * call "ip" with a root for each strongly connected component of the
1120 * graph (a root being a node from which all other nodes in the Scc
1121 * are reachable).
1122 *
1123 * Calling this function with "next_id" being the name of a node will
1124 * cause the library to call "ip" with all children of the node. Note
1125 * that cycles within an SCC are possible (including self-loops).
513 * 1126 *
514 * @param namespace namespace to inspect for updateable content 1127 * @param namespace namespace to inspect for updateable content
1128 * @param next_id ID to look for; use NULL to look for SCC roots
515 * @param ip function to call on each updateable identifier 1129 * @param ip function to call on each updateable identifier
516 * @param ip_cls closure for ip 1130 * @param ip_cls closure for ip
517 */ 1131 */
518void 1132void
519GNUNET_FS_namespace_list_updateable (struct GNUNET_FS_Namespace *namespace, 1133GNUNET_FS_namespace_list_updateable (struct GNUNET_FS_Namespace *namespace,
1134 const char *next_id,
520 GNUNET_FS_IdentifierProcessor ip, 1135 GNUNET_FS_IdentifierProcessor ip,
521 void *ip_cls) 1136 void *ip_cls)
522{ 1137{
523 GNUNET_break (0); 1138 unsigned int i;
524} 1139 unsigned int nug;
1140 GNUNET_HashCode hc;
1141 struct NamespaceUpdateNode *nsn;
1142 struct ProcessUpdateClosure pc;
1143 struct FindSccClosure fc;
525 1144
1145 if (namespace->update_nodes == NULL)
1146 read_update_information_graph (namespace);
1147 if (namespace->update_nodes == NULL)
1148 return; /* no nodes */
1149 if (namespace->update_map == NULL)
1150 {
1151 /* need to construct */
1152 namespace->update_map = GNUNET_CONTAINER_multihashmap_create (2 + 3 * namespace->update_node_count / 4);
1153 for (i=0;i<namespace->update_node_count;i++)
1154 {
1155 nsn = namespace->update_nodes[i];
1156 GNUNET_CRYPTO_hash (nsn->id,
1157 strlen (nsn->id),
1158 &hc);
1159 GNUNET_CONTAINER_multihashmap_put (namespace->update_map,
1160 &hc,
1161 nsn,
1162 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1163 }
1164 }
1165 if (next_id != NULL)
1166 {
1167 GNUNET_CRYPTO_hash (next_id,
1168 strlen (next_id),
1169 &hc);
1170 pc.ip = ip;
1171 pc.ip_cls = ip_cls;
1172 GNUNET_CONTAINER_multihashmap_get_multiple (namespace->update_map,
1173 &hc,
1174 &process_update_node,
1175 &pc);
1176 return;
1177 }
1178 /* Find heads of SCCs in update graph */
1179 nug = ++namespace->nug_gen;
1180 fc.scc_array = NULL;
1181 fc.scc_array_size = 0;
1182
1183 for (i=0;i<namespace->update_node_count;i++)
1184 {
1185 nsn = namespace->update_nodes[i];
1186 if (nsn->nug == nug)
1187 continue; /* already placed in SCC */
1188 GNUNET_CRYPTO_hash (nsn->update,
1189 strlen (nsn->update),
1190 &hc);
1191 nsn->nug = nug;
1192 fc.id = UINT_MAX;
1193 fc.nug = nug;
1194 fc.namespace = namespace;
1195 GNUNET_CONTAINER_multihashmap_get_multiple (namespace->update_map,
1196 &hc,
1197 &find_sccs,
1198 &fc);
1199 if (fc.id == UINT_MAX)
1200 {
1201 /* start new SCC */
1202 for (fc.id=0;fc.id<fc.scc_array_size;fc.id++)
1203 {
1204 if (fc.scc_array[fc.id] == NULL)
1205 {
1206 fc.scc_array[fc.id] = nsn;
1207 nsn->scc_id = fc.id;
1208 break;
1209 }
1210 }
1211 if (fc.id == fc.scc_array_size)
1212 {
1213 GNUNET_array_append (fc.scc_array,
1214 fc.scc_array_size,
1215 nsn);
1216 nsn->scc_id = fc.id;
1217 }
1218 /* put all nodes with same identifier into this SCC */
1219 GNUNET_CRYPTO_hash (nsn->id,
1220 strlen (nsn->id),
1221 &hc);
1222 fc.id = nsn->scc_id;
1223 fc.nug = nug;
1224 fc.namespace = namespace;
1225 GNUNET_CONTAINER_multihashmap_get_multiple (namespace->update_map,
1226 &hc,
1227 &find_sccs,
1228 &fc);
1229 }
1230 else
1231 {
1232 /* make head of SCC "id" */
1233 fc.scc_array[fc.id] = nsn;
1234 nsn->scc_id = fc.id;
1235 }
1236 }
1237 for (i=0;i<fc.scc_array_size;i++)
1238 {
1239 nsn = fc.scc_array[i];
1240 ip (ip_cls,
1241 nsn->id,
1242 nsn->uri,
1243 nsn->md,
1244 nsn->update);
1245 }
1246 GNUNET_array_grow (fc.scc_array,
1247 fc.scc_array_size,
1248 0);
1249}
526 1250
527 1251
528/* end of fs_namespace.c */ 1252/* end of fs_namespace.c */
diff --git a/src/fs/fs_publish.c b/src/fs/fs_publish.c
index 73fc710e1..2c9d41b05 100644
--- a/src/fs/fs_publish.c
+++ b/src/fs/fs_publish.c
@@ -1709,223 +1709,4 @@ GNUNET_FS_publish_ksk (struct GNUNET_FS_Handle *h,
1709} 1709}
1710 1710
1711 1711
1712/**
1713 * Context for the SKS publication.
1714 */
1715struct PublishSksContext
1716{
1717
1718 /**
1719 * Global FS context.
1720 */
1721 struct GNUNET_FS_Uri *uri;
1722
1723 /**
1724 * Handle to the datastore.
1725 */
1726 struct GNUNET_DATASTORE_Handle *dsh;
1727
1728 /**
1729 * Function to call once we're done.
1730 */
1731 GNUNET_FS_PublishContinuation cont;
1732
1733 /**
1734 * Closure for cont.
1735 */
1736 void *cont_cls;
1737
1738};
1739
1740
1741/**
1742 * Function called by the datastore API with
1743 * the result from the PUT (SBlock) request.
1744 *
1745 * @param cls closure of type "struct PublishSksContext*"
1746 * @param success GNUNET_OK on success
1747 * @param msg error message (or NULL)
1748 */
1749static void
1750sb_put_cont (void *cls,
1751 int success,
1752 const char *msg)
1753{
1754 struct PublishSksContext *psc = cls;
1755
1756 if (NULL != psc->dsh)
1757 {
1758 GNUNET_DATASTORE_disconnect (psc->dsh, GNUNET_NO);
1759 psc->dsh = NULL;
1760 }
1761 if (GNUNET_OK != success)
1762 psc->cont (psc->cont_cls,
1763 NULL,
1764 msg);
1765 else
1766 psc->cont (psc->cont_cls,
1767 psc->uri,
1768 NULL);
1769 GNUNET_FS_uri_destroy (psc->uri);
1770 GNUNET_free (psc);
1771}
1772
1773
1774/**
1775 * Publish an SBlock on GNUnet.
1776 *
1777 * @param h handle to the file sharing subsystem
1778 * @param namespace namespace to publish in
1779 * @param identifier identifier to use
1780 * @param update update identifier to use
1781 * @param meta metadata to use
1782 * @param uri URI to refer to in the SBlock
1783 * @param expirationTime when the SBlock expires
1784 * @param anonymity anonymity level for the SBlock
1785 * @param priority priority for the SBlock
1786 * @param options publication options
1787 * @param cont continuation
1788 * @param cont_cls closure for cont
1789 */
1790void
1791GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h,
1792 struct GNUNET_FS_Namespace *namespace,
1793 const char *identifier,
1794 const char *update,
1795 const struct GNUNET_CONTAINER_MetaData *meta,
1796 const struct GNUNET_FS_Uri *uri,
1797 struct GNUNET_TIME_Absolute expirationTime,
1798 uint32_t anonymity,
1799 uint32_t priority,
1800 enum GNUNET_FS_PublishOptions options,
1801 GNUNET_FS_PublishContinuation cont,
1802 void *cont_cls)
1803{
1804 struct PublishSksContext *psc;
1805 struct GNUNET_CRYPTO_AesSessionKey sk;
1806 struct GNUNET_CRYPTO_AesInitializationVector iv;
1807 struct GNUNET_FS_Uri *sks_uri;
1808 char *uris;
1809 size_t size;
1810 size_t slen;
1811 size_t nidlen;
1812 size_t idlen;
1813 ssize_t mdsize;
1814 struct SBlock *sb;
1815 struct SBlock *sb_enc;
1816 char *dest;
1817 struct GNUNET_CONTAINER_MetaData *mmeta;
1818 GNUNET_HashCode key; /* hash of thisId = key */
1819 GNUNET_HashCode id; /* hash of hc = identifier */
1820 GNUNET_HashCode query; /* id ^ nsid = DB query */
1821
1822 if (NULL == meta)
1823 mmeta = GNUNET_CONTAINER_meta_data_create ();
1824 else
1825 mmeta = GNUNET_CONTAINER_meta_data_duplicate (meta);
1826 uris = GNUNET_FS_uri_to_string (uri);
1827 slen = strlen (uris) + 1;
1828 idlen = strlen (identifier);
1829 if (update == NULL)
1830 update = "";
1831 nidlen = strlen (update) + 1;
1832 mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (mmeta);
1833 size = sizeof (struct SBlock) + slen + nidlen + mdsize;
1834 if (size > MAX_SBLOCK_SIZE)
1835 {
1836 size = MAX_SBLOCK_SIZE;
1837 mdsize = size - (sizeof (struct SBlock) + slen + nidlen);
1838 }
1839 sb = GNUNET_malloc (sizeof (struct SBlock) + size);
1840 dest = (char *) &sb[1];
1841 memcpy (dest, update, nidlen);
1842 dest += nidlen;
1843 memcpy (dest, uris, slen);
1844 GNUNET_free (uris);
1845 dest += slen;
1846 mdsize = GNUNET_CONTAINER_meta_data_serialize (mmeta,
1847 &dest,
1848 mdsize,
1849 GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
1850 GNUNET_CONTAINER_meta_data_destroy (mmeta);
1851 if (mdsize == -1)
1852 {
1853 GNUNET_break (0);
1854 GNUNET_free (sb);
1855 cont (cont_cls,
1856 NULL,
1857 _("Internal error."));
1858 return;
1859 }
1860 size = sizeof (struct SBlock) + mdsize + slen + nidlen;
1861 sb_enc = GNUNET_malloc (size);
1862 GNUNET_CRYPTO_hash (identifier, idlen, &key);
1863 GNUNET_CRYPTO_hash (&key, sizeof (GNUNET_HashCode), &id);
1864 sks_uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri));
1865 sks_uri->type = sks;
1866 GNUNET_CRYPTO_rsa_key_get_public (namespace->key, &sb_enc->subspace);
1867 GNUNET_CRYPTO_hash (&sb_enc->subspace,
1868 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1869 &sks_uri->data.sks.namespace);
1870 sks_uri->data.sks.identifier = GNUNET_strdup (identifier);
1871 GNUNET_CRYPTO_hash_xor (&id,
1872 &sks_uri->data.sks.namespace,
1873 &sb_enc->identifier);
1874 GNUNET_CRYPTO_hash_to_aes_key (&key, &sk, &iv);
1875 GNUNET_CRYPTO_aes_encrypt (&sb[1],
1876 size - sizeof (struct SBlock),
1877 &sk,
1878 &iv,
1879 &sb_enc[1]);
1880 sb_enc->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_SBLOCK);
1881 sb_enc->purpose.size = htonl(slen + mdsize + nidlen
1882 + sizeof(struct SBlock)
1883 - sizeof(struct GNUNET_CRYPTO_RsaSignature));
1884 GNUNET_assert (GNUNET_OK ==
1885 GNUNET_CRYPTO_rsa_sign (namespace->key,
1886 &sb_enc->purpose,
1887 &sb_enc->signature));
1888 psc = GNUNET_malloc (sizeof(struct PublishSksContext));
1889 psc->uri = sks_uri;
1890 psc->cont = cont;
1891 psc->cont_cls = cont_cls;
1892 if (0 != (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
1893 {
1894 GNUNET_free (sb_enc);
1895 GNUNET_free (sb);
1896 sb_put_cont (psc,
1897 GNUNET_OK,
1898 NULL);
1899 return;
1900 }
1901 psc->dsh = GNUNET_DATASTORE_connect (h->cfg, h->sched);
1902 if (NULL == psc->dsh)
1903 {
1904 GNUNET_free (sb_enc);
1905 GNUNET_free (sb);
1906 sb_put_cont (psc,
1907 GNUNET_NO,
1908 _("Failed to connect to datastore."));
1909 return;
1910 }
1911 GNUNET_CRYPTO_hash_xor (&sks_uri->data.sks.namespace,
1912 &id,
1913 &query);
1914 GNUNET_DATASTORE_put (psc->dsh,
1915 0,
1916 &sb_enc->identifier,
1917 size,
1918 sb_enc,
1919 GNUNET_BLOCK_TYPE_SBLOCK,
1920 priority,
1921 anonymity,
1922 expirationTime,
1923 -2, 1,
1924 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
1925 &sb_put_cont,
1926 psc);
1927 GNUNET_free (sb);
1928 GNUNET_free (sb_enc);
1929}
1930
1931/* end of fs_publish.c */ 1712/* end of fs_publish.c */