-fixing 2352
[oweals/gnunet.git] / src / fs / fs_namespace_advertise.c
1 /*
2      This file is part of GNUnet
3      (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 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_advertise.c
23  * @brief advertise namespaces (creating NBlocks)
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
34 /**
35  * Maximum legal size for an nblock.
36  */
37 #define MAX_NBLOCK_SIZE (60 * 1024)
38
39
40 /**
41  * Context for advertising a namespace.
42  */
43 struct GNUNET_FS_AdvertisementContext
44 {
45   /**
46    * Function to call with the result.
47    */
48   GNUNET_FS_PublishContinuation cont;
49
50   /**
51    * Closure for cont.
52    */
53   void *cont_cls;
54
55   /**
56    * Datastore handle.
57    */
58   struct GNUNET_DATASTORE_Handle *dsh;
59
60   /**
61    * Our KSK URI.
62    */
63   struct GNUNET_FS_Uri *ksk_uri;
64
65   /**
66    * Plaintext.
67    */
68   char *pt;
69
70   /**
71    * NBlock to sign and store.
72    */
73   struct NBlock *nb;
74
75   /**
76    * The namespace.
77    */
78   struct GNUNET_FS_Namespace *ns;
79
80   /**
81    * Current datastore queue entry for advertising.
82    */
83   struct GNUNET_DATASTORE_QueueEntry *dqe;
84
85   /**
86    * Block options.
87    */
88   struct GNUNET_FS_BlockOptions bo;
89
90   /**
91    * Number of bytes of plaintext.
92    */
93   size_t pt_size;
94
95   /**
96    * Current keyword offset.
97    */
98   unsigned int pos;
99 };
100
101
102 // FIXME: I see no good reason why this should need to be done
103 // in a new task (anymore).  Integrate with 'cancel' function below?
104 /**
105  * Disconnect from the datastore.
106  *
107  * @param cls datastore handle
108  * @param tc scheduler context
109  */
110 static void
111 do_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
112 {
113   struct GNUNET_DATASTORE_Handle *dsh = cls;
114
115   GNUNET_DATASTORE_disconnect (dsh, GNUNET_NO);
116 }
117
118
119 /**
120  * Continuation called to notify client about result of the
121  * operation.
122  *
123  * @param cls closure (our struct GNUNET_FS_AdvertismentContext)
124  * @param success GNUNET_SYSERR on failure
125  * @param min_expiration minimum expiration time required for content to be stored
126  * @param msg NULL on success, otherwise an error message
127  */
128 static void
129 advertisement_cont (void *cls, int success, 
130                     struct GNUNET_TIME_Absolute min_expiration,
131                     const char *msg)
132 {
133   struct GNUNET_FS_AdvertisementContext *ac = cls;
134   const char *keyword;
135   GNUNET_HashCode key;
136   GNUNET_HashCode query;
137   struct GNUNET_CRYPTO_AesSessionKey skey;
138   struct GNUNET_CRYPTO_AesInitializationVector iv;
139   struct GNUNET_CRYPTO_RsaPrivateKey *pk;
140
141   ac->dqe = NULL;
142   if (GNUNET_SYSERR == success)
143   {
144     /* error! */
145     (void) GNUNET_SCHEDULER_add_now (&do_disconnect, ac->dsh);
146     ac->dsh = NULL;
147     if (msg == NULL)
148     {
149       GNUNET_break (0);
150       msg = _("Unknown error");
151     }
152     if (ac->cont != NULL)
153     {
154       ac->cont (ac->cont_cls, NULL, msg);
155       ac->cont = NULL;
156     }
157     GNUNET_FS_namespace_advertise_cancel (ac);
158     return;
159   }
160   if (ac->pos == ac->ksk_uri->data.ksk.keywordCount)
161   {
162     /* done! */
163     (void) GNUNET_SCHEDULER_add_now (&do_disconnect, ac->dsh);
164     ac->dsh = NULL;
165     if (ac->cont != NULL)
166     {
167       ac->cont (ac->cont_cls, ac->ksk_uri, NULL);
168       ac->cont = NULL;
169     }
170     GNUNET_FS_namespace_advertise_cancel (ac);
171     return;
172   }
173   keyword = ac->ksk_uri->data.ksk.keywords[ac->pos++];
174   /* first character of keyword indicates if it is
175    * mandatory or not -- ignore for hashing */
176   GNUNET_CRYPTO_hash (&keyword[1], strlen (&keyword[1]), &key);
177   GNUNET_CRYPTO_hash_to_aes_key (&key, &skey, &iv);
178   GNUNET_CRYPTO_aes_encrypt (ac->pt, ac->pt_size, &skey, &iv, &ac->nb[1]);
179   GNUNET_break (GNUNET_OK ==
180                 GNUNET_CRYPTO_rsa_sign (ac->ns->key, &ac->nb->ns_purpose,
181                                         &ac->nb->ns_signature));
182   pk = GNUNET_CRYPTO_rsa_key_create_from_hash (&key);
183   GNUNET_assert (pk != NULL);
184   GNUNET_CRYPTO_rsa_key_get_public (pk, &ac->nb->keyspace);
185   GNUNET_CRYPTO_hash (&ac->nb->keyspace,
186                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
187                       &query);
188   GNUNET_break (GNUNET_OK ==
189                 GNUNET_CRYPTO_rsa_sign (pk, &ac->nb->ksk_purpose,
190                                         &ac->nb->ksk_signature));
191   GNUNET_CRYPTO_rsa_key_free (pk);
192   ac->dqe = GNUNET_DATASTORE_put (ac->dsh, 0 /* no reservation */ ,
193                                   &query, ac->pt_size + sizeof (struct NBlock), ac->nb,
194                                   GNUNET_BLOCK_TYPE_FS_NBLOCK, ac->bo.content_priority,
195                                   ac->bo.anonymity_level, ac->bo.replication_level,
196                                   ac->bo.expiration_time, -2, 1,
197                                   GNUNET_CONSTANTS_SERVICE_TIMEOUT, &advertisement_cont,
198                                   ac);
199 }
200
201
202 /**
203  * Publish an advertismement for a namespace.
204  *
205  * @param h handle to the file sharing subsystem
206  * @param ksk_uri keywords to use for advertisment
207  * @param namespace handle for the namespace that should be advertised
208  * @param meta meta-data for the namespace advertisement
209  * @param bo block options
210  * @param rootEntry name of the root of the namespace
211  * @param cont continuation
212  * @param cont_cls closure for cont
213  * @return NULL on error ('cont' is still called)
214  */
215 struct GNUNET_FS_AdvertisementContext *
216 GNUNET_FS_namespace_advertise (struct GNUNET_FS_Handle *h,
217                                struct GNUNET_FS_Uri *ksk_uri,
218                                struct GNUNET_FS_Namespace *namespace,
219                                const struct GNUNET_CONTAINER_MetaData *meta,
220                                const struct GNUNET_FS_BlockOptions *bo,
221                                const char *rootEntry,
222                                GNUNET_FS_PublishContinuation cont,
223                                void *cont_cls)
224 {
225   size_t reslen;
226   size_t size;
227   ssize_t mdsize;
228   struct NBlock *nb;
229   char *mdst;
230   struct GNUNET_DATASTORE_Handle *dsh;
231   struct GNUNET_FS_AdvertisementContext *ctx;
232   char *pt;
233
234   /* create advertisements */
235   mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta);
236   if (-1 == mdsize)
237   {
238     cont (cont_cls, NULL, _("Failed to serialize meta data"));
239     return NULL;
240   }
241   reslen = strlen (rootEntry) + 1;
242   size = mdsize + sizeof (struct NBlock) + reslen;
243   if (size > MAX_NBLOCK_SIZE)
244   {
245     size = MAX_NBLOCK_SIZE;
246     mdsize = size - sizeof (struct NBlock) - reslen;
247   }
248
249   pt = GNUNET_malloc (mdsize + reslen);
250   memcpy (pt, rootEntry, reslen);
251   mdst = &pt[reslen];
252   mdsize =
253       GNUNET_CONTAINER_meta_data_serialize (meta, &mdst, mdsize,
254                                             GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
255   if (-1 == mdsize)
256   {
257     GNUNET_break (0);
258     GNUNET_free (pt);
259     cont (cont_cls, NULL, _("Failed to serialize meta data"));
260     return NULL;
261   }
262   size = mdsize + sizeof (struct NBlock) + reslen;
263   nb = GNUNET_malloc (size);
264   GNUNET_CRYPTO_rsa_key_get_public (namespace->key, &nb->subspace);
265   nb->ns_purpose.size =
266       htonl (mdsize + reslen +
267              sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
268              sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
269   nb->ns_purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK);
270   nb->ksk_purpose.size =
271       htonl (size - sizeof (struct GNUNET_CRYPTO_RsaSignature));
272   nb->ksk_purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK_KSIG);
273   dsh = GNUNET_DATASTORE_connect (h->cfg);
274   if (NULL == dsh)
275   {
276     GNUNET_free (nb);
277     GNUNET_free (pt);
278     cont (cont_cls, NULL, _("Failed to connect to datastore service"));
279     return NULL;
280   }
281   ctx = GNUNET_malloc (sizeof (struct GNUNET_FS_AdvertisementContext));
282   ctx->cont = cont;
283   ctx->cont_cls = cont_cls;
284   ctx->dsh = dsh;
285   ctx->ksk_uri = GNUNET_FS_uri_dup (ksk_uri);
286   ctx->nb = nb;
287   ctx->pt = pt;
288   ctx->pt_size = mdsize + reslen;
289   ctx->ns = namespace;
290   ctx->ns->rc++;
291   ctx->bo = *bo;
292   advertisement_cont (ctx, GNUNET_OK, GNUNET_TIME_UNIT_ZERO_ABS, NULL);
293   return ctx;
294 }
295
296
297 /**
298  * Abort the namespace advertisement operation.
299  *
300  * @param ac context of the operation to abort.
301  */
302 void
303 GNUNET_FS_namespace_advertise_cancel (struct GNUNET_FS_AdvertisementContext *ac)
304 {
305   if (NULL != ac->dqe)
306   {
307     GNUNET_DATASTORE_cancel (ac->dqe);
308     ac->dqe = NULL;
309   }
310   if (NULL != ac->dsh)
311   {
312     GNUNET_DATASTORE_disconnect (ac->dsh, GNUNET_NO);
313     ac->dsh = NULL;
314   }
315   GNUNET_FS_uri_destroy (ac->ksk_uri);
316   GNUNET_free (ac->pt);
317   GNUNET_free (ac->nb);
318   GNUNET_FS_namespace_delete (ac->ns, GNUNET_NO);
319   GNUNET_free (ac);
320 }
321
322
323 /* end of fs_namespace_advertise.c */